Skip to content

ui/ux fixes#1459

Merged
abdulhdr1 merged 31 commits intomainfrom
abdul/13-10-25-ux-bugfixes
Oct 15, 2025
Merged

ui/ux fixes#1459
abdulhdr1 merged 31 commits intomainfrom
abdul/13-10-25-ux-bugfixes

Conversation

@abdulhdr1
Copy link
Copy Markdown
Contributor

@abdulhdr1 abdulhdr1 commented Oct 13, 2025

What is this contribution about?

Fixes:

Screenshots/Demonstration

Screen.Recording.2025-10-13.at.18.22.50.mov

Review Checklist

  • PR title is clear and descriptive
  • Changes are tested and working
  • Documentation is updated (if needed)
  • No breaking changes

Summary by CodeRabbit

  • New Features

    • Unified chat supporting Agent and decopilot modes with per‑mode state, responsive multi‑panel layout, mobile preview toggle and floating controls.
    • Topbar mode switch with avatars (lazy‑loaded) and exported topbar controls.
    • Chat input/resources accept an optional right‑side action area.
    • New ButtonGroup UI component for grouped controls.
  • UX Improvements

    • Decopilot panel hidden on agent detail pages.
    • Removed automatic scrolling to tool results.
    • Improved drag‑and‑drop leave handling.
    • Agent name updated to "decochat".
  • Chores

    • UI dependency bumped.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 13, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Replaces single Chat with UnifiedChat/ChatWithProvider and adds a PreviewContext for URL-synced chatMode and mobile preview toggles; extends ChatInput/ContextResources with a rightNode; adds ButtonGroup UI and a Radix dependency bump; gates decopilot panel rendering and adds dragleave handling.

Changes

Cohort / File(s) Summary
Agent edit unified layout & context
apps/web/src/components/agent/edit.tsx
Introduces PreviewContext/usePreviewContext, URL-driven chatMode, UnifiedChat and ChatWithProvider, ResponsiveLayout, per-mode state preservation, decopilot tools/rules wiring, and mobile preview/floating controls.
Chat input / resources extensibility
apps/web/src/components/chat/chat-input.tsx, apps/web/src/components/chat/context-resources.tsx
ChatInput and ContextResources accept an optional rightNode?: ReactNode; header layout reworked into left/right blocks, items consolidated, and rightNode rendered for extensibility (e.g., preview toggle).
Topbar / project controls & mode switch
apps/web/src/components/layout/project.tsx, apps/web/src/components/layout/topbar.tsx
Adds TopbarControls export and AgentChatModeSwitch to toggle agent↔decopilot via URL params using AgentAvatar; Topbar now lazy-loads TopbarControls inside Suspense.
Decopilot layout conditional rendering
apps/web/src/components/layout/decopilot-layout.tsx
Uses useLocation to compute isAgentDetailPage and renders the Decopilot panel only when decopilotOpen && not on agent detail pages.
Integrations tab behavior
apps/web/src/components/integrations/tabs/connection-tabs.tsx
Removes setTimeout-based scrollIntoView after tool calls and collapses inline spacing in V2Section.
Drag lifecycle handling
apps/web/src/hooks/use-file-upload.ts
Adds global dragleave event listener wired to existing handler and ensures cleanup.
UI components & dependency bump
packages/ui/src/components/button-group.tsx, packages/ui/package.json
Adds ButtonGroup, ButtonGroupText, ButtonGroupSeparator, buttonGroupVariants; bumps @radix-ui/react-slot to ^1.2.3.
Constants metadata
packages/sdk/src/constants.ts
Changes WELL_KNOWN_AGENTS.decopilotAgent.name from "Deco Chat" to "decochat" (metadata only).
Agent provider imports reorg
apps/web/src/components/agent/provider.tsx
Reorders/consolidates imports and exposes additional symbols (Toolset, WELL_KNOWN_AGENTS, UIMessage) — import-level/type changes only.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Topbar as TopbarControls
  participant Router as Browser (URL)
  participant AgentEdit as Agent Edit Page
  participant PreviewCtx as PreviewContext
  participant ChatWrap as ChatWithProvider
  participant AgentChat as Agent Chat
  participant DecoChat as Decopilot Chat

  User->>Topbar: click mode switch (agent | decopilot)
  Topbar->>Router: update URL query `chat=agent|decopilot`
  Router-->>AgentEdit: location with `chat` param
  AgentEdit->>PreviewCtx: sync `chatMode` from URL
  AgentEdit->>ChatWrap: render ChatWithProvider with `chatMode`
  alt chatMode == agent
    ChatWrap->>AgentChat: mount Agent provider + UI
  else chatMode == decopilot
    ChatWrap->>DecoChat: mount Decopilot provider + UI (tools/rules)
  end
Loading
sequenceDiagram
  autonumber
  participant Browser as Router (pathname)
  participant Layout as DecopilotLayout
  participant Panel as Decopilot Panel

  Browser-->>Layout: provide pathname & decopilotOpen
  Layout->>Layout: compute isAgentDetailPage = /\/agent\/[^\/]+\/[^\/]+$/
  alt decopilotOpen && !isAgentDetailPage
    Layout->>Panel: render Decopilot panel
  else
    Layout--x Panel: do not render panel
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • lucis
  • tlgimenes
  • igorbrasileiro

Poem

I hop between modes, soft paws on code,
Two chats, two pockets, each safely stowed.
A floating button twinkles near my den,
Preview peeks and rules tuck in their pen.
Hooray — a rabbit’s patchwork, humming then 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title “ui/ux fixes” is overly generic and does not convey the specific nature of the changes, making it difficult for reviewers or maintainers to understand the primary update at a glance. Please update the title to clearly reflect the main change, for example “Introduce unified chat component with mobile preview toggles and decopilot mode support,” so that it succinctly summarizes the key update.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed The PR description follows the repository’s template by providing a “What is this contribution about?” section with linked issue fixes, a “Screenshots/Demonstration” link, and a completed review checklist, thereby covering all required sections and information.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4013af and a0eefae.

📒 Files selected for processing (6)
  • apps/web/src/components/agent/provider.tsx (2 hunks)
  • apps/web/src/components/chat/chat-input.tsx (2 hunks)
  • apps/web/src/components/chat/context-resources.tsx (5 hunks)
  • apps/web/src/hooks/use-file-upload.ts (1 hunks)
  • packages/sdk/src/constants.ts (1 hunks)
  • packages/ui/package.json (1 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@abdulhdr1 abdulhdr1 changed the title fix(agent/edit): add background color to chat component ui/ux fixes Oct 13, 2025
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Oct 13, 2025

Deploying chat with  Cloudflare Pages  Cloudflare Pages

Latest commit: f2175a7
Status: ✅  Deploy successful!
Preview URL: https://728c4775.chat-46r.pages.dev
Branch Preview URL: https://abdul-13-10-25-ux-bugfixes.chat-46r.pages.dev

View logs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (11)
apps/web/src/components/agent/edit.tsx (5)

132-148: Prevent header overlap on long agent names

Absolute-positioned buttons + pr-24 can cause name overlap/truncation issues. Add min-w-0 to the row and truncate the title.

-          <div
-            className={cn(
-              "flex items-center gap-2 w-full pr-24",
-              isEmpty ? "hidden" : "",
-            )}
-          >
+          <div
+            className={cn(
+              "flex items-center gap-2 w-full pr-24 min-w-0",
+              isEmpty ? "hidden" : "",
+            )}
+          >
             <AgentAvatar url={agent.avatar} fallback={agent.name} size="sm" />
-            <h1 className="text-sm font-medium tracking-tight">{agent.name}</h1>
+            <h1 className="text-sm font-medium tracking-tight truncate">{agent.name}</h1>

Also applies to: 123-130


342-390: Avoid nesting DecopilotLayout inside an existing DecopilotLayout

This double layout adds an extra ResizablePanelGroup and a nested provider, increasing complexity and potential layout quirks without functional gain (the page is already wrapped by DecopilotLayout). Render the chat providers directly.

-  return (
-    <DecopilotLayout value={decopilotContextValue}>
-      <div className="h-full w-full">
+  return (
+      <div className="h-full w-full">
         {/* Agent chat - hidden when in decopilot mode */}
         <div className={chatMode === "agent" ? "block h-full" : "hidden"}>
           <AgentProvider
             agentId={agentId || ""}
             threadId={agentThreadId}
             uiOptions={{
               showThreadTools: false,
               showEditAgent: false,
               showModelSelector: false,
               showThreadMessages: false,
               showAgentVisibility: false,
             }}
           >
             <UnifiedChat />
           </AgentProvider>
         </div>

         {/* Decopilot chat - hidden when in agent mode */}
         <div className={chatMode === "decopilot" ? "block h-full" : "hidden"}>
           <AgentProvider
             key={threadState.threadId}
             agentId={WELL_KNOWN_AGENTS.decopilotAgent.id}
             threadId={decopilotThreadId}
             initialInput={
               shouldUseInitialInput
                 ? (threadState.initialMessage ?? undefined)
                 : undefined
             }
             autoSend={shouldUseInitialInput ? threadState.autoSend : false}
             onAutoSendComplete={clearThreadState}
             additionalTools={allAdditionalTools}
             initialRules={allRules}
             onToolCall={onToolCall}
             uiOptions={{
               showThreadTools: false,
               showEditAgent: false,
               showModelSelector: true,
               showThreadMessages: false,
               showAgentVisibility: false,
             }}
           >
             <UnifiedChat />
           </AgentProvider>
         </div>
-      </div>
-    </DecopilotLayout>
+      </div>
   );

364-373: Align key and threadId to avoid unintended remounts without changing transport thread

key={threadState.threadId} forces a remount while threadId stays decopilotThreadId, which may reset UI state without starting a new thread. Align both, or drop the key.

Options:

  • A) Align to thread state when present:
-          <AgentProvider
-            key={threadState.threadId}
-            agentId={WELL_KNOWN_AGENTS.decopilotAgent.id}
-            threadId={decopilotThreadId}
+          <AgentProvider
+            key={threadState.threadId ?? decopilotThreadId}
+            agentId={WELL_KNOWN_AGENTS.decopilotAgent.id}
+            threadId={threadState.threadId ?? decopilotThreadId}
  • B) If the intent is a stable per-mode thread, remove key and keep decopilotThreadId:
-          <AgentProvider
-            key={threadState.threadId}
+          <AgentProvider
             agentId={WELL_KNOWN_AGENTS.decopilotAgent.id}
             threadId={decopilotThreadId}

Please confirm which behavior you want (stable per-mode vs. new thread per trigger).

Also applies to: 286-289


432-444: Sync chatMode changes back to the URL for deep-links

State is synced from URL→state, but not state→URL. Persisting chat parameter improves shareability and refresh resilience.

- import { useLocation, useParams } from "react-router";
+ import { useLocation, useParams, useNavigate } from "react-router";
   const location = useLocation();
+  const navigate = useNavigate();
   const searchParams = new URLSearchParams(location.search);
   const urlChatMode =
     (searchParams.get("chat") as "agent" | "decopilot") || "agent";
 // Sync with URL changes
 useEffect(() => {
   setChatMode(urlChatMode);
 }, [urlChatMode]);
 
+// Persist state changes back to URL
+useEffect(() => {
+  const sp = new URLSearchParams(location.search);
+  if (sp.get("chat") !== chatMode) {
+    sp.set("chat", chatMode);
+    navigate({ pathname: location.pathname, search: sp.toString() }, { replace: true });
+  }
+  // eslint-disable-next-line react-hooks/exhaustive-deps
+}, [chatMode, location.pathname]);

Also applies to: 37-37


270-276: Mobile FAB safe-area padding (optional)

On iOS, the fixed FAB can collide with the home indicator. Consider adding safe-area padding.

Example:

  • Add inline style: style={{ bottom: "max(env(safe-area-inset-bottom), 1.5rem)" }}
  • Or Tailwind arbitrary value if enabled: bottom-[max(env(safe-area-inset-bottom),1.5rem)]
packages/ui/src/components/button-group.tsx (2)

24-36: Set a resolved orientation for data attributes to avoid undefined.

When orientation is omitted, data-orientation becomes undefined. Resolve it to match cva’s default.

-function ButtonGroup({
-  className,
-  orientation,
-  ...props
-}: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
-  return (
-    <div
-      role="group"
-      data-slot="button-group"
-      data-orientation={orientation}
-      className={cn(buttonGroupVariants({ orientation }), className)}
-      {...props}
-    />
-  );
-}
+function ButtonGroup({
+  className,
+  orientation,
+  ...props
+}: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
+  const resolved = orientation ?? "horizontal";
+  return (
+    <div
+      role="group"
+      data-slot="button-group"
+      data-orientation={resolved}
+      className={cn(buttonGroupVariants({ orientation: resolved }), className)}
+      {...props}
+    />
+  );
+}

40-58: Consider forwardRef for better interoperability.

Forward refs on ButtonGroupText (and ButtonGroup) improve integration with parent layouts and focus management. Optional but recommended.

apps/web/src/hooks/use-file-upload.ts (1)

3-3: Use DOM DragEvent types for global listeners (not React.DragEvent).

Global addEventListener receives native events. Typing these as React.DragEvent obscures intent and can mislead.

-import type { DragEvent } from "react";
+// No React DragEvent needed for global listeners; use DOM DragEvent
-function handleFileDrop(e: DragEvent) {
+function handleFileDrop(e: DragEvent) {
   e.preventDefault();
   const fileList = e.dataTransfer?.files;
   if (fileList?.length) {
     uploadFileList(fileList);
   }
 }
-const dragEvent = e as unknown as DragEvent;
+const dragEvent = e as DragEvent;

Optionally stabilize handlers with useCallback to avoid re-subscribing on each render.

Also applies to: 93-101, 135-141

apps/web/src/components/layout/decopilot-layout.tsx (1)

37-39: Use boolean regex test for clarity.

Avoid relying on truthiness of match results.

-const isAgentDetailPage = location.pathname.match(/\/agent\/[^\/]+\/[^\/]+$/);
+const isAgentDetailPage = /\/agent\/[^/]+\/[^/]+$/.test(location.pathname);
apps/web/src/components/layout/project.tsx (1)

242-258: TopbarControls routing logic LGTM.

Correctly shows mode switch on agent detail pages and Decopilot toggle elsewhere. Consider normalizing the agent-detail test to boolean as in decopilot-layout for consistency.

apps/web/src/components/chat/context-resources.tsx (1)

277-277: Remove unnecessary wrapper div.

The rightNode doesn't need to be wrapped in a div since it's already a ReactNode and can be rendered directly.

Apply this diff to simplify:

-        {rightNode && <div>{rightNode}</div>}
+        {rightNode}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0947e09 and ffc280c.

📒 Files selected for processing (10)
  • apps/web/src/components/agent/edit.tsx (6 hunks)
  • apps/web/src/components/chat/chat-input.tsx (3 hunks)
  • apps/web/src/components/chat/context-resources.tsx (3 hunks)
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx (1 hunks)
  • apps/web/src/components/layout/decopilot-layout.tsx (2 hunks)
  • apps/web/src/components/layout/project.tsx (5 hunks)
  • apps/web/src/components/layout/topbar.tsx (2 hunks)
  • apps/web/src/hooks/use-file-upload.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/src/components/button-group.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
{apps/web,packages/{sdk,ui}}/package.json

📄 CodeRabbit inference engine (.cursor/rules/structure.mdc)

Maintain a package.json in each workspace (apps/web, packages/sdk, packages/ui)

Files:

  • packages/ui/package.json
packages/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep shared logic (UI kit, SDK, runtime, CLI tooling) under packages/

Files:

  • packages/ui/package.json
  • packages/ui/src/components/button-group.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.{ts,tsx}: MCP tools must use Zod schemas for input and, when applicable, output validation
Register tools with server.registerTool providing description, inputSchema.shape, and optional outputSchema.shape
In every MCP tool handler, perform authorization checks first and then call context.resourceAccess.grant() before business logic
Name tools using the {RESOURCE}_{ACTION} pattern (e.g., AGENTS_CREATE, THREADS_LIST)
Group related tools into typed collections (e.g., GLOBAL_TOOLS, WORKSPACE_TOOLS) and export them as const
Always check workspace/team access before executing operations that touch workspace resources
Return proper authorization errors and handle forbidden operations explicitly

Prefer specific TypeScript types over any

**/*.{ts,tsx}: Write concise, maintainable, and technically accurate TypeScript code
Use functional and declarative programming patterns; avoid classes
Favor iteration and modularization to follow DRY and avoid code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Organize files so each contains only related content (components, subcomponents, helpers, static content, types)
Prefer interfaces over types for object shapes
Avoid enums; use maps (objects/records) instead
Use the function keyword for pure functions to benefit from hoisting and clarity
Ensure dependency arrays use stable references; do not inline new objects/arrays/functions
Memoize options/objects used in hooks (e.g., useMemo for options passed to useMemo/useCallback)
Favor named exports for functions

Files:

  • packages/ui/src/components/button-group.tsx
  • apps/web/src/hooks/use-file-upload.ts
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/chat/context-resources.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.tsx: Use the shared KEYS object to construct consistent React Query keys
Use useSuspenseQuery for critical data fetching hooks
Implement optimistic updates for mutations and provide rollback on error via onMutate/onError
After successful mutations, update relevant caches with setQueryData (e.g., entity detail and list keys)
Leverage React Query’s built-in request deduplication instead of manual throttling
Use parallel queries where appropriate to reduce total load time

**/*.tsx: Use functional React components typed with TypeScript interfaces
Prefer using existing UI components from packages/ui over custom duplicates
Always use design system components from @deco/ui in UI code instead of hand-rolled equivalents
Memoize expensive computations with useMemo (e.g., filtering/sorting)
Memoize objects/arrays used in renders to keep stable references (useMemo)
Use useDeferredValue to keep search inputs responsive during heavy filtering
Follow MCP Tool data-access patterns (e.g., useAgents, useIntegrations) with proper loading/error states
Prefer react-hook-form with schema validation (e.g., zod) over manual useState for forms
Avoid prop drilling for forms by using a form context/provider
Adhere to Single Responsibility Principle by splitting large components into focused subcomponents
Design for composability and reusability of small UI components (e.g., Avatar variants)
Provide consistent loading and error states for data-driven components (e.g., Spinner, ErrorMessage, EmptyState)
Extract complex inline logic from JSX (avoid IIFEs) into small components/functions

Files:

  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/chat/context-resources.tsx
packages/ui/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/structure.mdc)

Place reusable design system components (shadcn/ui based) under packages/ui/src

Files:

  • packages/ui/src/components/button-group.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Biome formatting: use two-space indentation and double quotes
Keep imports sorted
Name hooks and utility functions using camelCase

Files:

  • packages/ui/src/components/button-group.tsx
  • apps/web/src/hooks/use-file-upload.ts
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/chat/context-resources.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components and classes using PascalCase

Files:

  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/chat/context-resources.tsx
packages/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Enforce kebab-case filenames in shared packages

Files:

  • packages/ui/src/components/button-group.tsx
{apps/web,packages}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Tailwind design tokens consistent with the design system

Files:

  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/chat/context-resources.tsx
packages/ui/src/components/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react-ts.mdc)

Use design system form primitives (Form, FormField, FormItem, etc.) when building forms

Files:

  • packages/ui/src/components/button-group.tsx
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

Log authorization failures to aid debugging and auditing

Files:

  • apps/web/src/hooks/use-file-upload.ts
apps/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

apps/web/**/*.{js,jsx,ts,tsx}: Use each feature flag in as few places as possible; if a flag must appear at multiple callsites, explicitly flag this for careful developer review
Gate any flag-dependent code behind checks that verify the flag’s values are valid and expected
If a custom person or event property is referenced in two or more files or at two or more callsites in the same file, centralize the keys in an enum (TS) or const object (JS)

Files:

  • apps/web/src/hooks/use-file-upload.ts
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/chat/context-resources.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

In TypeScript, store feature flag names in an enum with members written UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention

Files:

  • apps/web/src/hooks/use-file-upload.ts
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/chat/context-resources.tsx
apps/web/**

📄 CodeRabbit inference engine (AGENTS.md)

Place the Vite/React web client in apps/web

Files:

  • apps/web/src/hooks/use-file-upload.ts
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/chat/context-resources.tsx
🧬 Code graph analysis (6)
packages/ui/src/components/button-group.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/web/src/components/layout/topbar.tsx (1)
apps/web/src/components/layout/project.tsx (1)
  • TopbarControls (242-258)
apps/web/src/components/layout/decopilot-layout.tsx (1)
apps/web/src/components/decopilot/context.tsx (1)
  • DecopilotProvider (18-24)
apps/web/src/components/agent/edit.tsx (11)
apps/web/src/components/agent/provider.tsx (2)
  • useAgent (600-604)
  • AgentProvider (151-597)
apps/web/src/components/agents/hooks.ts (1)
  • useFocusChat (13-45)
apps/web/src/components/chat/chat-messages.tsx (1)
  • ChatMessages (35-155)
apps/web/src/components/chat/chat-input.tsx (1)
  • ChatInput (20-211)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/decopilot/thread-context.tsx (1)
  • useDecopilotThread (100-108)
apps/web/src/components/decopilot/use-app-additional-tools.ts (1)
  • useAppAdditionalTools (4-24)
apps/web/src/components/decopilot/context.tsx (1)
  • useDecopilotContext (26-29)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (282-338)
apps/web/src/components/layout/decopilot-layout.tsx (1)
  • DecopilotLayout (32-56)
packages/ui/src/hooks/use-mobile.ts (1)
  • useIsMobile (7-21)
apps/web/src/components/layout/project.tsx (3)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/common/avatar/agent.tsx (1)
  • AgentAvatar (21-71)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (282-338)
apps/web/src/components/chat/context-resources.tsx (1)
apps/web/src/components/integrations/select-connection-dialog.tsx (1)
  • SelectConnectionDialog (860-893)
🪛 GitHub Actions: Tests
apps/web/src/components/chat/chat-input.tsx

[error] 23-26: Formatter would have printed the following content: adjust destructuring braces and spacing. Run 'bun run fmt' to apply formatting.

apps/web/src/components/integrations/tabs/connection-tabs.tsx

[error] 732-734: Formatter would have printed the following content: insert additional braces and adjust whitespace in the rendered block. Run 'bun run fmt' to apply formatting.

🔇 Additional comments (11)
apps/web/src/components/agent/edit.tsx (2)

309-317: Decopilot rules/tools wiring looks solid

Merging appAdditionalTools + contextTools and combining decopilot + context rules is correct for mode-specific chat context. LGTM.

Also applies to: 326-335


119-121: bg-sidebar is a valid design token
The --sidebar and related CSS variables are defined in packages/ui/src/styles/global.css.

apps/web/src/hooks/use-file-upload.ts (1)

164-172: Good addition: handle dragleave to reset dragging state.

This aligns drag lifecycle better. Watch for potential flicker when moving between child elements; if observed, gate with relatedTarget checks or a dragenter/leave depth counter.

apps/web/src/components/layout/decopilot-layout.tsx (1)

44-46: Gating DecopilotChat on agent detail pages looks good.

Prevents duplicate chat surfaces. Matches TopbarControls behavior elsewhere.

apps/web/src/components/chat/chat-input.tsx (1)

129-139: rightNode passthrough looks good.

Clean extension point for ContextResources.

apps/web/src/components/layout/topbar.tsx (1)

9-9: TopbarControls integration LGTM.

Centralizes header chat controls; aligns with routing/visibility logic.

Also applies to: 57-57

apps/web/src/components/layout/project.tsx (3)

161-170: Guard useAgentData against missing id / Suspense boundary.

If params.id is undefined or no Suspense boundary wraps TopbarControls, this can suspend or error. Consider skipping fetch when no id, or wrap AgentChatModeSwitch in .

Do we have a Suspense boundary above TopbarControls on agent detail pages? If not, I can propose a minimal wrapper.


175-179: URL mode switch is clean.

replace: true preserves history hygiene; preserves other query params.


229-236: Avatar-based Chat trigger LGTM.

Better visual consistency vs static img.

packages/ui/package.json (1)

36-36: No conflicting @radix-ui/react-slot versions detected
Only packages/ui declares ^1.2.3; no other workspace pins a different version.

apps/web/src/components/chat/context-resources.tsx (1)

43-43: LGTM! Good extensibility addition.

The rightNode prop enables the component to accept custom UI elements (e.g., preview toggles), improving composability and reusability.

Also applies to: 54-54

Comment on lines +4 to +9
import {
type FormEvent,
type KeyboardEvent,
type ReactNode,
useEffect,
} from "react";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Collapse import specifiers; remove trailing comma.

Conform to formatter to fix CI.

-import {
-  type FormEvent,
-  type KeyboardEvent,
-  type ReactNode,
-  useEffect,
-} from "react";
+import { type FormEvent, type KeyboardEvent, type ReactNode, useEffect } from "react";
📝 Committable suggestion

‼️ 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.

Suggested change
import {
type FormEvent,
type KeyboardEvent,
type ReactNode,
useEffect,
} from "react";
import { type FormEvent, type KeyboardEvent, type ReactNode, useEffect } from "react";
🤖 Prompt for AI Agents
In apps/web/src/components/chat/chat-input.tsx around lines 4 to 9, the import
specifiers are spread across multiple lines and include a trailing comma which
fails the formatter; collapse the specifiers into a single-line import and
remove the trailing comma so the statement becomes a single-line import of
FormEvent, KeyboardEvent, ReactNode and useEffect from "react".

Comment on lines +20 to +23
export function ChatInput({
disabled,
rightNode,
}: { disabled?: boolean; rightNode?: ReactNode } = {}) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Compact parameter destructuring to satisfy formatter.

-export function ChatInput({
-  disabled,
-  rightNode,
-}: { disabled?: boolean; rightNode?: ReactNode } = {}) {
+export function ChatInput({ disabled, rightNode }: { disabled?: boolean; rightNode?: ReactNode } = {}) {
📝 Committable suggestion

‼️ 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.

Suggested change
export function ChatInput({
disabled,
rightNode,
}: { disabled?: boolean; rightNode?: ReactNode } = {}) {
export function ChatInput({ disabled, rightNode }: { disabled?: boolean; rightNode?: ReactNode } = {}) {
🤖 Prompt for AI Agents
In apps/web/src/components/chat/chat-input.tsx around lines 20 to 23, the
function parameter destructuring is split across lines which breaks the
formatter; collapse the signature into a single line so the props and their type
are compact (e.g., place the destructured props and their type annotation and
default value all on one line) and ensure the file still imports ReactNode if
required.

Comment thread apps/web/src/components/chat/context-resources.tsx Outdated
Comment thread apps/web/src/components/integrations/tabs/connection-tabs.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/src/hooks/use-file-upload.ts (2)

141-173: Dragleave on window can prematurely clear isDragging; use a drag counter with dragenter/dragleave

dragleave will fire when moving between child elements, causing flicker. Track nesting with a counter so you only clear when the last leave occurs (or on drop/dragend).

@@
-    let skip = false;
+    let skip = false;
+    let dragCounter = 0;
@@
-    function handleDragOver(e: Event) {
+    function handleDragOver(e: Event) {
       if (skip) {
         return;
       }
       e.preventDefault();
       setIsDragging(true);
     }
+    function handleDragEnter(e: Event) {
+      if (skip) return;
+      e.preventDefault();
+      dragCounter++;
+      setIsDragging(true);
+    }
     function handleDragEnd() {
       skip = false;
-      setIsDragging(false);
+      dragCounter = 0;
+      setIsDragging(false);
     }
+    function handleDragLeave() {
+      if (skip) return;
+      dragCounter = Math.max(0, dragCounter - 1);
+      if (dragCounter === 0) {
+        setIsDragging(false);
+      }
+    }
@@
-    globalThis.addEventListener("dragover", handleDragOver);
+    globalThis.addEventListener("dragenter", handleDragEnter);
+    globalThis.addEventListener("dragover", handleDragOver);
     globalThis.addEventListener("dragend", handleDragEnd);
-    globalThis.addEventListener("dragleave", handleDragEnd);
+    globalThis.addEventListener("dragleave", handleDragLeave);
@@
-      globalThis.removeEventListener("dragover", handleDragOver);
+      globalThis.removeEventListener("dragenter", handleDragEnter);
+      globalThis.removeEventListener("dragover", handleDragOver);
       globalThis.removeEventListener("dragend", handleDragEnd);
-      globalThis.removeEventListener("dragleave", handleDragEnd);
+      globalThis.removeEventListener("dragleave", handleDragLeave);

3-3: Type mismatch: avoid casting DOM Event to React.DragEvent; use DOM DragEvent or alias React’s type

You import React’s DragEvent and then cast a native Event to it. Prefer the DOM DragEvent and, if needed, alias React’s type for component handlers.

-import type { DragEvent } from "react";
+import type { DragEvent as ReactDragEvent } from "react";
@@
-  function handleFileDrop(e: DragEvent) {
+  function handleFileDrop(e: DragEvent | ReactDragEvent) {
@@
-      const dragEvent = e as unknown as DragEvent;
-      handleFileDrop(dragEvent);
+      handleFileDrop(e as DragEvent);

Optionally, be explicit with DOM type in this module:

// helper alias at top if desired
type DragEvent = globalThis.DragEvent;

Also applies to: 135-141

🧹 Nitpick comments (9)
packages/ui/src/components/button-group.tsx (2)

7-22: Consider simplifying the complex selector chain.

The base class string on line 8 contains highly complex selectors with nested pseudo-classes, particularly:

  • has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md
  • [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit

These selectors may be fragile and difficult to maintain if the DOM structure or component composition changes. Consider refactoring to use more explicit component props or simpler CSS patterns.


60-76: Investigate the need for !important in margin reset.

Line 70 uses !m-0 (equivalent to margin: 0 !important), which indicates a potential specificity conflict with existing Separator styles. Using !important can make styles harder to maintain and override in the future.

Consider whether the underlying Separator component's margin can be removed or if a more specific selector would work without !important.

apps/web/src/hooks/use-file-upload.ts (1)

126-174: Listeners are re-bound every render; stabilize with a ref or memoize the handler

The effect depends on handleFileDrop (new identity each render), so listeners are added/removed repeatedly. Use a ref to hold the latest callback and bind listeners once.

@@
-  // Global file drop handler
-  useEffect(() => {
+  // Keep latest handleFileDrop in a ref
+  const handleFileDropRef = useRef(handleFileDrop);
+  useEffect(() => {
+    handleFileDropRef.current = handleFileDrop;
+  }, [handleFileDrop]);
+
+  // Global file drop handler
+  useEffect(() => {
@@
-    function handleDrop(e: Event) {
+    function handleDrop(e: Event) {
       setIsDragging(false);
       skip = false;
-      const dragEvent = e as unknown as DragEvent;
-      handleFileDrop(dragEvent);
+      handleFileDropRef.current(e as DragEvent);
     }
@@
-  }, [handleFileDrop]);
+  }, []); // listeners bound once

To verify reduced churn, you can log add/remove counts locally or profile with React DevTools.

apps/web/src/components/layout/decopilot-layout.tsx (1)

37-46: Make route check boolean and handle optional trailing slash

isAgentDetailPage is a match array. Use .test() for a boolean and slightly relax for a trailing slash.

-  const isAgentDetailPage = location.pathname.match(/\/agent\/[^\/]+\/[^\/]+$/);
+  const isAgentDetailPage = /\/agent\/[^/]+\/[^/]+\/?$/.test(location.pathname);
@@
-        {decopilotOpen && !isAgentDetailPage && (
+        {decopilotOpen && !isAgentDetailPage && (
apps/web/src/components/layout/project.tsx (1)

242-246: Normalize isAgentDetailPage to boolean

Keep semantics consistent with decopilot-layout and avoid RegExpMatchArray truthiness.

-  const isAgentDetailPage = location.pathname.match(/\/agent\/[^\/]+\/[^\/]+$/);
+  const isAgentDetailPage = /\/agent\/[^/]+\/[^/]+\/?$/.test(location.pathname);
apps/web/src/components/chat/chat-input.tsx (2)

66-70: Prefer shared mobile detection hook

Use useIsMobile() from @deco/ui/hooks/use-mobile.ts for consistency and SSR safety instead of UA checks here.

-  const isMobile =
-    typeof window !== "undefined" &&
-    ("ontouchstart" in window ||
-      navigator.userAgent.toLowerCase().includes("mobile"));
+  const isMobile = useIsMobile();

Remember to import: import { useIsMobile } from "@deco/ui/hooks/use-mobile.ts";


141-142: Render rightNode as a footer fallback when showContextResources is false

rightNode is only passed into <ContextResources> (gated by showContextResources), so it never appears in the input footer when that flag is off. To always show it (e.g. mobile toggle), insert a fallback render before the send button:

@@ apps/web/src/components/chat/chat-input.tsx
     <div className="flex items-center gap-2">
       {showModelSelector && <ModelSelector … />}
       <AudioButton onMessage={handleRichTextChange} />
+      {!showContextResources && rightNode}
       <Button … />
     </div>
apps/web/src/components/agent/edit.tsx (2)

361-387: Keying AgentProvider vs. threadId mismatch

The Decopilot AgentProvider is keyed by threadState.threadId but receives threadId={decopilotThreadId} (a stable UUID). This forces remounts without actually switching thread IDs. Either bind the prop to the same threadState.threadId you key on, or remove the key if a stable thread per mode is desired.

-  <AgentProvider
-    key={threadState.threadId}
+  <AgentProvider
+    key={threadState.threadId}
     agentId={WELL_KNOWN_AGENTS.decopilotAgent.id}
-    threadId={decopilotThreadId}
+    threadId={threadState.threadId ?? decopilotThreadId}

Ensure threadState.threadId is defined when you expect a reset; otherwise fall back to the stable id.


426-444: Chat mode derived from URL but not pushed back on toggles

You read chat from location.search and expose setChatMode, but updates don’t update the URL. Consider syncing changes to the query param to preserve deep-links and back/forward behavior.

   const [chatMode, setChatMode] = useState<"agent" | "decopilot">(urlChatMode);
@@
-  useEffect(() => {
-    setChatMode(urlChatMode);
-  }, [urlChatMode]);
+  useEffect(() => {
+    setChatMode(urlChatMode);
+  }, [urlChatMode]);
+
+  // Optionally: push updates to URL when chatMode changes
+  const location = useLocation();
+  const navigate = useNavigate(); // import from react-router
+  useEffect(() => {
+    const sp = new URLSearchParams(location.search);
+    if (sp.get("chat") !== chatMode) {
+      sp.set("chat", chatMode);
+      navigate({ search: `?${sp.toString()}` }, { replace: true });
+    }
+  }, [chatMode, location.search, navigate]);

As per coding guidelines: favor declarative UX and predictable navigation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0947e09 and 15b8ce6.

📒 Files selected for processing (10)
  • apps/web/src/components/agent/edit.tsx (6 hunks)
  • apps/web/src/components/chat/chat-input.tsx (3 hunks)
  • apps/web/src/components/chat/context-resources.tsx (3 hunks)
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx (0 hunks)
  • apps/web/src/components/layout/decopilot-layout.tsx (2 hunks)
  • apps/web/src/components/layout/project.tsx (5 hunks)
  • apps/web/src/components/layout/topbar.tsx (2 hunks)
  • apps/web/src/hooks/use-file-upload.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/src/components/button-group.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
🧰 Additional context used
📓 Path-based instructions (14)
{apps/web,packages/{sdk,ui}}/package.json

📄 CodeRabbit inference engine (.cursor/rules/structure.mdc)

Maintain a package.json in each workspace (apps/web, packages/sdk, packages/ui)

Files:

  • packages/ui/package.json
packages/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep shared logic (UI kit, SDK, runtime, CLI tooling) under packages/

Files:

  • packages/ui/package.json
  • packages/ui/src/components/button-group.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.{ts,tsx}: MCP tools must use Zod schemas for input and, when applicable, output validation
Register tools with server.registerTool providing description, inputSchema.shape, and optional outputSchema.shape
In every MCP tool handler, perform authorization checks first and then call context.resourceAccess.grant() before business logic
Name tools using the {RESOURCE}_{ACTION} pattern (e.g., AGENTS_CREATE, THREADS_LIST)
Group related tools into typed collections (e.g., GLOBAL_TOOLS, WORKSPACE_TOOLS) and export them as const
Always check workspace/team access before executing operations that touch workspace resources
Return proper authorization errors and handle forbidden operations explicitly

Prefer specific TypeScript types over any

**/*.{ts,tsx}: Write concise, maintainable, and technically accurate TypeScript code
Use functional and declarative programming patterns; avoid classes
Favor iteration and modularization to follow DRY and avoid code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Organize files so each contains only related content (components, subcomponents, helpers, static content, types)
Prefer interfaces over types for object shapes
Avoid enums; use maps (objects/records) instead
Use the function keyword for pure functions to benefit from hoisting and clarity
Ensure dependency arrays use stable references; do not inline new objects/arrays/functions
Memoize options/objects used in hooks (e.g., useMemo for options passed to useMemo/useCallback)
Favor named exports for functions

Files:

  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/hooks/use-file-upload.ts
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.tsx: Use the shared KEYS object to construct consistent React Query keys
Use useSuspenseQuery for critical data fetching hooks
Implement optimistic updates for mutations and provide rollback on error via onMutate/onError
After successful mutations, update relevant caches with setQueryData (e.g., entity detail and list keys)
Leverage React Query’s built-in request deduplication instead of manual throttling
Use parallel queries where appropriate to reduce total load time

**/*.tsx: Use functional React components typed with TypeScript interfaces
Prefer using existing UI components from packages/ui over custom duplicates
Always use design system components from @deco/ui in UI code instead of hand-rolled equivalents
Memoize expensive computations with useMemo (e.g., filtering/sorting)
Memoize objects/arrays used in renders to keep stable references (useMemo)
Use useDeferredValue to keep search inputs responsive during heavy filtering
Follow MCP Tool data-access patterns (e.g., useAgents, useIntegrations) with proper loading/error states
Prefer react-hook-form with schema validation (e.g., zod) over manual useState for forms
Avoid prop drilling for forms by using a form context/provider
Adhere to Single Responsibility Principle by splitting large components into focused subcomponents
Design for composability and reusability of small UI components (e.g., Avatar variants)
Provide consistent loading and error states for data-driven components (e.g., Spinner, ErrorMessage, EmptyState)
Extract complex inline logic from JSX (avoid IIFEs) into small components/functions

Files:

  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/layout/topbar.tsx
apps/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

apps/web/**/*.{js,jsx,ts,tsx}: Use each feature flag in as few places as possible; if a flag must appear at multiple callsites, explicitly flag this for careful developer review
Gate any flag-dependent code behind checks that verify the flag’s values are valid and expected
If a custom person or event property is referenced in two or more files or at two or more callsites in the same file, centralize the keys in an enum (TS) or const object (JS)

Files:

  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/hooks/use-file-upload.ts
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

In TypeScript, store feature flag names in an enum with members written UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention

Files:

  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/hooks/use-file-upload.ts
apps/web/**

📄 CodeRabbit inference engine (AGENTS.md)

Place the Vite/React web client in apps/web

Files:

  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/hooks/use-file-upload.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Biome formatting: use two-space indentation and double quotes
Keep imports sorted
Name hooks and utility functions using camelCase

Files:

  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/hooks/use-file-upload.ts
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components and classes using PascalCase

Files:

  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/layout/topbar.tsx
{apps/web,packages}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Tailwind design tokens consistent with the design system

Files:

  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/layout/topbar.tsx
packages/ui/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/structure.mdc)

Place reusable design system components (shadcn/ui based) under packages/ui/src

Files:

  • packages/ui/src/components/button-group.tsx
packages/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Enforce kebab-case filenames in shared packages

Files:

  • packages/ui/src/components/button-group.tsx
packages/ui/src/components/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react-ts.mdc)

Use design system form primitives (Form, FormField, FormItem, etc.) when building forms

Files:

  • packages/ui/src/components/button-group.tsx
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

Log authorization failures to aid debugging and auditing

Files:

  • apps/web/src/hooks/use-file-upload.ts
🧬 Code graph analysis (6)
apps/web/src/components/agent/edit.tsx (11)
apps/web/src/components/agent/provider.tsx (2)
  • useAgent (600-604)
  • AgentProvider (151-597)
apps/web/src/components/agents/hooks.ts (1)
  • useFocusChat (13-45)
apps/web/src/components/chat/chat-messages.tsx (1)
  • ChatMessages (35-155)
apps/web/src/components/chat/chat-input.tsx (1)
  • ChatInput (20-214)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/decopilot/thread-context.tsx (1)
  • useDecopilotThread (100-108)
apps/web/src/components/decopilot/use-app-additional-tools.ts (1)
  • useAppAdditionalTools (4-24)
apps/web/src/components/decopilot/context.tsx (1)
  • useDecopilotContext (26-29)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (282-338)
apps/web/src/components/layout/decopilot-layout.tsx (1)
  • DecopilotLayout (32-56)
packages/ui/src/hooks/use-mobile.ts (1)
  • useIsMobile (7-21)
apps/web/src/components/layout/decopilot-layout.tsx (2)
apps/web/src/components/decopilot/context.tsx (1)
  • DecopilotProvider (18-24)
packages/ui/src/components/resizable.tsx (2)
  • ResizablePanelGroup (56-56)
  • ResizablePanel (56-56)
packages/ui/src/components/button-group.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/web/src/components/chat/context-resources.tsx (1)
apps/web/src/components/integrations/select-connection-dialog.tsx (1)
  • SelectConnectionDialog (860-893)
apps/web/src/components/layout/project.tsx (3)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/common/avatar/agent.tsx (1)
  • AgentAvatar (21-71)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (282-338)
apps/web/src/components/layout/topbar.tsx (1)
apps/web/src/components/layout/project.tsx (1)
  • TopbarControls (242-258)
🔇 Additional comments (15)
packages/ui/src/components/button-group.tsx (2)

24-38: LGTM!

The ButtonGroup component is well-structured with proper accessibility attributes (role="group"), data attributes for styling hooks, and correct variant application.


40-58: LGTM!

ButtonGroupText correctly implements the Slot pattern for polymorphic rendering, allowing flexible composition with the asChild prop. The styling is comprehensive and follows design system patterns.

packages/ui/package.json (1)

36-36: @radix-ui/react-slot@1.2.3 exists with no known security vulnerabilities.

apps/web/src/components/chat/context-resources.tsx (1)

43-55: rightNode extension point looks good

Non-breaking optional slot, memo-free, and safely rendered. LGTM.

Confirm that call sites pass stable elements (memoized where expensive) to avoid re-renders.

Also applies to: 276-278

apps/web/src/components/chat/chat-input.tsx (2)

4-9: Type import for ReactNode looks good

Using type ReactNode is correct and tree-shake friendly.


20-26: Propagate right-side slot via rightNode

API shape is clear and backward‑compatible.

apps/web/src/components/agent/edit.tsx (9)

60-79: PreviewContext setup is clean

Type-safe context + guard hook; fits the usage pattern in this file.


118-148: Header layout changes prevent shifts

Absolute positioning for actions and reserved padding (pr-24) is a good call to avoid layout jitter.


155-156: Good use of rightNode to surface mobile toggle in chat

Passing rightNode={<PreviewToggleButton />} aligns with the new slot and keeps concerns separated.


218-236: Mobile-only PreviewToggleButton

Simple and clear; returns null on desktop.


270-275: Floating mobile toggle

Floating action placement for mobile is sensible and non-intrusive.


472-489: Provider composition is sensible

PreviewContext wraps AgentProvider; ResponsiveLayout uses both correctly.


294-336: Guard decopilot-only context merges

Merging rules and tools only in decopilot mode is correct. Minor: if both appAdditionalTools and contextTools share keys, later values override earlier; confirm this is intended.


309-317: agentId fallback safety

Returning null when !chatAgentId is fine; given Page throws when agentId is missing, this is effectively dead-path. Safe to keep.


293-301: Remove invalid thread provider warning ProjectLayout already wraps all child routes (including agent/edit) in DecopilotThreadProvider, so useDecopilotThread is always used within its provider.

Likely an incorrect or invalid review comment.

Comment thread apps/web/src/components/agent/edit.tsx Outdated
Comment thread apps/web/src/components/layout/project.tsx
Comment thread apps/web/src/components/layout/topbar.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (12)
apps/web/src/components/chat/context-resources.tsx (1)

276-277: Remove unnecessary wrapper div around rightNode.

The extra <div> wrapper around rightNode is unnecessary and adds an extra DOM node without styling or semantic purpose.

Apply this diff to simplify:

-        {/* Optional right node (e.g., preview toggle) */}
-        {rightNode && <div>{rightNode}</div>}
+        {rightNode}
packages/ui/package.json (1)

51-53: Consider moving React deps to peerDependencies to avoid duplicate React instances

As a UI library, React and ReactDOM are typically peerDependencies to prevent multiple React copies in consuming apps.

Apply this diff:

   "dependencies": {
@@
-    "react": "^19.2.0",
-    "react-day-picker": "^8.10.1",
-    "react-dom": "^19.2.0",
+    "react-day-picker": "^8.10.1",
@@
   },
+  "peerDependencies": {
+    "react": "^18.2.0 || ^19.0.0",
+    "react-dom": "^18.2.0 || ^19.0.0"
+  },
packages/ui/src/components/button-group.tsx (5)

4-4: Avoid self-import inside the same package; use a relative path for cn

Self-imports can cause duplicate module instances and complicate bundlers. Prefer a relative import.

-import { cn } from "@deco/ui/lib/utils.ts";
+import { cn } from "../lib/utils.ts";

1-6: Prepare for ref forwarding by importing React

Forwarding refs will require the React runtime import.

+import * as React from "react";
 import { Slot } from "@radix-ui/react-slot";
 import { cva, type VariantProps } from "class-variance-authority";
 
-import { cn } from "@deco/ui/lib/utils.ts";
+import { cn } from "../lib/utils.ts";
 import { Separator } from "./separator";

24-38: Forward refs for ButtonGroup for better composability and focus management

Enables parent components to control focus/measure and aligns with common DS patterns.

-function ButtonGroup({
-  className,
-  orientation,
-  ...props
-}: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
-  return (
-    <div
-      role="group"
-      data-slot="button-group"
-      data-orientation={orientation}
-      className={cn(buttonGroupVariants({ orientation }), className)}
-      {...props}
-    />
-  );
-}
+const ButtonGroup = React.forwardRef<
+  HTMLDivElement,
+  React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>
+>(({ className, orientation, ...props }, ref) => {
+  return (
+    <div
+      ref={ref}
+      role="group"
+      data-slot="button-group"
+      data-orientation={orientation}
+      className={cn(buttonGroupVariants({ orientation }), className)}
+      {...props}
+    />
+  );
+});
+ButtonGroup.displayName = "ButtonGroup";

40-58: Forward refs and keep polymorphic asChild support in ButtonGroupText

Allows consumers to attach refs regardless of asChild usage.

-function ButtonGroupText({
-  className,
-  asChild = false,
-  ...props
-}: React.ComponentProps<"div"> & {
-  asChild?: boolean;
-}) {
-  const Comp = asChild ? Slot : "div";
-
-  return (
-    <Comp
-      className={cn(
-        "bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
-        className,
-      )}
-      {...props}
-    />
-  );
-}
+const ButtonGroupText = React.forwardRef<
+  HTMLDivElement,
+  React.ComponentProps<"div"> & { asChild?: boolean }
+>(({ className, asChild = false, ...props }, ref) => {
+  const Comp = asChild ? Slot : "div";
+  return (
+    <Comp
+      ref={ref}
+      className={cn(
+        "bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
+        className,
+      )}
+      {...props}
+    />
+  );
+});
+ButtonGroupText.displayName = "ButtonGroupText";

60-76: Forward refs through ButtonGroupSeparator to the underlying Separator

Keeps parity with Separator’s ref behavior and improves ergonomics.

-function ButtonGroupSeparator({
-  className,
-  orientation = "vertical",
-  ...props
-}: React.ComponentProps<typeof Separator>) {
-  return (
-    <Separator
-      data-slot="button-group-separator"
-      orientation={orientation}
-      className={cn(
-        "bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto",
-        className,
-      )}
-      {...props}
-    />
-  );
-}
+const ButtonGroupSeparator = React.forwardRef<
+  React.ElementRef<typeof Separator>,
+  React.ComponentPropsWithoutRef<typeof Separator>
+>(({ className, orientation = "vertical", ...props }, ref) => {
+  return (
+    <Separator
+      ref={ref}
+      data-slot="button-group-separator"
+      orientation={orientation}
+      className={cn(
+        "bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto",
+        className,
+      )}
+      {...props}
+    />
+  );
+});
+ButtonGroupSeparator.displayName = "ButtonGroupSeparator";
apps/web/src/components/agent/edit.tsx (1)

341-389: Avoid nested ResizablePanelGroup; use DecopilotProvider instead of DecopilotLayout here.

FormProvider already wraps with DecopilotLayout. The inner DecopilotLayout in ChatWithProvider nests panel groups and adds redundant layout logic (even if gated off). Wrap chat with DecopilotProvider to set rules without layout duplication.

@@
-import { DecopilotLayout } from "../layout/decopilot-layout.tsx";
+import { DecopilotLayout } from "../layout/decopilot-layout.tsx";
+import { DecopilotProvider } from "../decopilot/context.tsx";
@@
-  return (
-    <DecopilotLayout value={decopilotContextValue}>
-      <div className="h-full w-full">
+  return (
+    <DecopilotProvider value={decopilotContextValue}>
+      <div className="h-full w-full">
@@
-      </div>
-    </DecopilotLayout>
+      </div>
+    </DecopilotProvider>
   );

Also applies to: 471-489

apps/web/src/components/layout/project.tsx (3)

160-178: Prefer useSearchParams for query updates.

Simplifies reads/writes and avoids manual URL string building.

-import { Link, Outlet, useLocation, useNavigate, useParams } from "react-router";
+import { Link, Outlet, useLocation, useNavigate, useParams, useSearchParams } from "react-router";
@@
-  const location = useLocation();
-  const navigate = useNavigate();
+  const location = useLocation();
+  const navigate = useNavigate();
+  const [searchParams, setSearchParams] = useSearchParams();
@@
-  const searchParams = new URLSearchParams(location.search);
@@
-  const handleModeChange = (mode: "agent" | "decopilot") => {
-    const newParams = new URLSearchParams(location.search);
-    newParams.set("chat", mode);
-    navigate(`${location.pathname}?${newParams.toString()}`, { replace: true });
-  };
+  const handleModeChange = (mode: "agent" | "decopilot") => {
+    searchParams.set("chat", mode);
+    setSearchParams(searchParams, { replace: true });
+  };

182-214: Add aria-pressed to toggle buttons for accessibility.

Expose the current state to assistive tech.

-      <Button
+      <Button
         size="sm"
         variant={currentMode === "agent" ? "special" : "outline"}
         onClick={() => handleModeChange("agent")}
+        aria-pressed={currentMode === "agent"}
         className="flex items-center gap-1.5"
       >
@@
-      <Button
+      <Button
         size="sm"
         variant={currentMode === "decopilot" ? "special" : "outline"}
         onClick={() => handleModeChange("decopilot")}
+        aria-pressed={currentMode === "decopilot"}
         className="flex items-center gap-1.5"
       >

241-257: Extract shared agent-detail detection hook

Inline regex /agent/[^/]+/[^/]+$/ is duplicated in:

  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/settings/integrations.tsx
  • apps/web/src/components/agents/hooks.ts
  • apps/web/src/components/settings/usage/agents-table.tsx

Create a useIsAgentDetailRoute (or similar) hook that uses React Router’s useMatch('/agent/:agentId/:threadId'), then replace all inline regex checks with this hook.

apps/web/src/components/layout/decopilot-layout.tsx (1)

37-46: Extract agent-detail path logic into a shared helper or use React Router’s useMatch

Multiple files construct or detect /agent/:id/:threadId (e.g., decopilot-layout, integrations.tsx, agents-table.tsx, agents/hooks.ts). Centralize this pattern in an isAgentDetailPath(pathname) util or replace the regex with useMatch("/agent/:agentId/:threadId") to prevent duplication and drift.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0947e09 and d764d73.

📒 Files selected for processing (10)
  • apps/web/src/components/agent/edit.tsx (6 hunks)
  • apps/web/src/components/chat/chat-input.tsx (3 hunks)
  • apps/web/src/components/chat/context-resources.tsx (3 hunks)
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx (0 hunks)
  • apps/web/src/components/layout/decopilot-layout.tsx (2 hunks)
  • apps/web/src/components/layout/project.tsx (5 hunks)
  • apps/web/src/components/layout/topbar.tsx (2 hunks)
  • apps/web/src/hooks/use-file-upload.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/src/components/button-group.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.{ts,tsx}: MCP tools must use Zod schemas for input and, when applicable, output validation
Register tools with server.registerTool providing description, inputSchema.shape, and optional outputSchema.shape
In every MCP tool handler, perform authorization checks first and then call context.resourceAccess.grant() before business logic
Name tools using the {RESOURCE}_{ACTION} pattern (e.g., AGENTS_CREATE, THREADS_LIST)
Group related tools into typed collections (e.g., GLOBAL_TOOLS, WORKSPACE_TOOLS) and export them as const
Always check workspace/team access before executing operations that touch workspace resources
Return proper authorization errors and handle forbidden operations explicitly

Prefer specific TypeScript types over any

**/*.{ts,tsx}: Write concise, maintainable, and technically accurate TypeScript code
Use functional and declarative programming patterns; avoid classes
Favor iteration and modularization to follow DRY and avoid code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Organize files so each contains only related content (components, subcomponents, helpers, static content, types)
Prefer interfaces over types for object shapes
Avoid enums; use maps (objects/records) instead
Use the function keyword for pure functions to benefit from hoisting and clarity
Ensure dependency arrays use stable references; do not inline new objects/arrays/functions
Memoize options/objects used in hooks (e.g., useMemo for options passed to useMemo/useCallback)
Favor named exports for functions

Files:

  • apps/web/src/hooks/use-file-upload.ts
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

Log authorization failures to aid debugging and auditing

Files:

  • apps/web/src/hooks/use-file-upload.ts
apps/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

apps/web/**/*.{js,jsx,ts,tsx}: Use each feature flag in as few places as possible; if a flag must appear at multiple callsites, explicitly flag this for careful developer review
Gate any flag-dependent code behind checks that verify the flag’s values are valid and expected
If a custom person or event property is referenced in two or more files or at two or more callsites in the same file, centralize the keys in an enum (TS) or const object (JS)

Files:

  • apps/web/src/hooks/use-file-upload.ts
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

In TypeScript, store feature flag names in an enum with members written UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention

Files:

  • apps/web/src/hooks/use-file-upload.ts
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
apps/web/**

📄 CodeRabbit inference engine (AGENTS.md)

Place the Vite/React web client in apps/web

Files:

  • apps/web/src/hooks/use-file-upload.ts
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Biome formatting: use two-space indentation and double quotes
Keep imports sorted
Name hooks and utility functions using camelCase

Files:

  • apps/web/src/hooks/use-file-upload.ts
  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.tsx: Use the shared KEYS object to construct consistent React Query keys
Use useSuspenseQuery for critical data fetching hooks
Implement optimistic updates for mutations and provide rollback on error via onMutate/onError
After successful mutations, update relevant caches with setQueryData (e.g., entity detail and list keys)
Leverage React Query’s built-in request deduplication instead of manual throttling
Use parallel queries where appropriate to reduce total load time

**/*.tsx: Use functional React components typed with TypeScript interfaces
Prefer using existing UI components from packages/ui over custom duplicates
Always use design system components from @deco/ui in UI code instead of hand-rolled equivalents
Memoize expensive computations with useMemo (e.g., filtering/sorting)
Memoize objects/arrays used in renders to keep stable references (useMemo)
Use useDeferredValue to keep search inputs responsive during heavy filtering
Follow MCP Tool data-access patterns (e.g., useAgents, useIntegrations) with proper loading/error states
Prefer react-hook-form with schema validation (e.g., zod) over manual useState for forms
Avoid prop drilling for forms by using a form context/provider
Adhere to Single Responsibility Principle by splitting large components into focused subcomponents
Design for composability and reusability of small UI components (e.g., Avatar variants)
Provide consistent loading and error states for data-driven components (e.g., Spinner, ErrorMessage, EmptyState)
Extract complex inline logic from JSX (avoid IIFEs) into small components/functions

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components and classes using PascalCase

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
{apps/web,packages}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Tailwind design tokens consistent with the design system

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/chat/chat-input.tsx
  • packages/ui/src/components/button-group.tsx
  • apps/web/src/components/layout/decopilot-layout.tsx
  • apps/web/src/components/agent/edit.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
packages/ui/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/structure.mdc)

Place reusable design system components (shadcn/ui based) under packages/ui/src

Files:

  • packages/ui/src/components/button-group.tsx
packages/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep shared logic (UI kit, SDK, runtime, CLI tooling) under packages/

Files:

  • packages/ui/src/components/button-group.tsx
  • packages/ui/package.json
packages/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Enforce kebab-case filenames in shared packages

Files:

  • packages/ui/src/components/button-group.tsx
packages/ui/src/components/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react-ts.mdc)

Use design system form primitives (Form, FormField, FormItem, etc.) when building forms

Files:

  • packages/ui/src/components/button-group.tsx
{apps/web,packages/{sdk,ui}}/package.json

📄 CodeRabbit inference engine (.cursor/rules/structure.mdc)

Maintain a package.json in each workspace (apps/web, packages/sdk, packages/ui)

Files:

  • packages/ui/package.json
🧬 Code graph analysis (5)
apps/web/src/components/chat/context-resources.tsx (1)
apps/web/src/components/integrations/select-connection-dialog.tsx (1)
  • SelectConnectionDialog (860-893)
packages/ui/src/components/button-group.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/web/src/components/agent/edit.tsx (8)
apps/web/src/components/agent/provider.tsx (2)
  • useAgent (600-604)
  • AgentProvider (151-597)
apps/web/src/components/agents/hooks.ts (1)
  • useFocusChat (13-45)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/decopilot/thread-context.tsx (1)
  • useDecopilotThread (100-108)
apps/web/src/components/decopilot/use-app-additional-tools.ts (1)
  • useAppAdditionalTools (4-24)
apps/web/src/components/decopilot/context.tsx (1)
  • useDecopilotContext (26-29)
apps/web/src/components/layout/decopilot-layout.tsx (1)
  • DecopilotLayout (32-56)
packages/ui/src/hooks/use-mobile.ts (1)
  • useIsMobile (7-21)
apps/web/src/components/layout/topbar.tsx (1)
apps/web/src/components/layout/project.tsx (1)
  • TopbarControls (241-257)
apps/web/src/components/layout/project.tsx (3)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/common/avatar/agent.tsx (1)
  • AgentAvatar (21-71)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (282-338)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (7)
apps/web/src/components/chat/context-resources.tsx (2)

43-43: LGTM!

The rightNode prop addition allows flexible UI composition by enabling parent components to inject custom content into the context resources area.


176-177: Manually verify responsive behavior of the new flex layout
This is the sole use of justify-between items-end in chat context; test:

  • Multiple integrations/files/rules wrapping to multiple lines
  • Mobile viewport behavior with items-end alignment
  • Alignment of the preview toggle (rightNode) when content wraps
apps/web/src/components/chat/chat-input.tsx (1)

4-9: LGTM!

The rightNode prop is properly typed, threaded through to ContextResources, and enables flexible UI composition. The implementation follows React best practices for prop drilling of optional render nodes.

Also applies to: 20-26, 141-141

packages/ui/src/components/button-group.tsx (1)

7-22: Verify Tailwind v4 safelisting for complex arbitrary variants

Classes like has-[…]:[…]:rounded-r-md and nested selectors may need safelisting depending on your Tailwind v4 config.

Please confirm your Tailwind config scans TSX files and safelists these patterns if necessary to avoid purging. If needed, I can draft a safelist snippet. As per coding guidelines.

packages/ui/package.json (1)

36-36: All @radix-ui/react-slot versions are consistent
Only packages/ui/package.json declares @radix-ui/react-slot@^1.2.3; no mismatches found across workspaces.

apps/web/src/components/layout/decopilot-layout.tsx (1)

45-52: Conditional render looks good.

Gating DecopilotChat on agent-detail pages prevents UI overlap.

apps/web/src/components/layout/topbar.tsx (1)

55-58: LGTM: TopbarControls integration.

Import and usage are correct; enables context-aware controls.

Comment thread apps/web/src/components/agent/edit.tsx Outdated
Comment thread apps/web/src/components/chat/context-resources.tsx Outdated
globalThis.addEventListener("drag", handleDrag);
globalThis.addEventListener("dragover", handleDragOver);
globalThis.addEventListener("dragend", handleDragEnd);
globalThis.addEventListener("dragleave", handleDragEnd);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Global dragleave listener will cause isDragging state to flicker.

The dragleave event fires whenever the pointer exits any element boundary—including transitions between parent and child elements. At the global level, this means dragleave will fire constantly during a drag operation as the mouse crosses element boundaries within the page. Combined with dragover (which sets isDragging(true)), this creates a rapid true→false→true flickering of the drag state, degrading the user experience and potentially breaking drag-and-drop UI.

If the intent is to detect when files are dragged outside the browser window, use a reference-counting pattern instead:

  useEffect(() => {
    let skip = false;
+   let dragDepth = 0;

    function handleDrop(e: Event) {
      setIsDragging(false);
+     dragDepth = 0;
      skip = false;
      const dragEvent = e as unknown as DragEvent;
      handleFileDrop(dragEvent);
    }
    function handleDragOver(e: Event) {
      if (skip) {
        return;
      }
      e.preventDefault();
      setIsDragging(true);
    }
+   function handleDragEnter(e: Event) {
+     if (skip) {
+       return;
+     }
+     dragDepth++;
+     setIsDragging(true);
+   }
+   function handleDragLeave() {
+     if (skip) {
+       return;
+     }
+     dragDepth--;
+     if (dragDepth === 0) {
+       setIsDragging(false);
+     }
+   }
    function handleDragEnd() {
      skip = false;
+     dragDepth = 0;
      setIsDragging(false);
    }
    function handleDrag() {
      skip = true;
    }

    globalThis.addEventListener("drop", handleDrop);
    globalThis.addEventListener("drag", handleDrag);
+   globalThis.addEventListener("dragenter", handleDragEnter);
+   globalThis.addEventListener("dragleave", handleDragLeave);
    globalThis.addEventListener("dragover", handleDragOver);
    globalThis.addEventListener("dragend", handleDragEnd);
-   globalThis.addEventListener("dragleave", handleDragEnd);

    return () => {
      globalThis.removeEventListener("drop", handleDrop);
      globalThis.removeEventListener("drag", handleDrag);
+     globalThis.removeEventListener("dragenter", handleDragEnter);
+     globalThis.removeEventListener("dragleave", handleDragLeave);
      globalThis.removeEventListener("dragover", handleDragOver);
      globalThis.removeEventListener("dragend", handleDragEnd);
-     globalThis.removeEventListener("dragleave", handleDragEnd);
    };
  }, [handleFileDrop]);

Please clarify which of the issues (#1410, #1411, #1412, #1409) this change addresses and the specific UX problem you observed. This will help determine the correct fix.

Also applies to: 171-171


🏁 Script executed:

#!/bin/bash
rg -n "addEventListener.*dragleave" -C2 apps/web/src/hooks/use-file-upload.ts
rg -n "function handleDragEnd" -C2 apps/web/src/hooks/use-file-upload.ts
rg -n "dragenter" -C2 apps/web/src/hooks/use-file-upload.ts

Length of output: 352


Replace global dragleave listener—implement depth-aware or scoped logic to prevent flicker
The global dragleave→handleDragEnd fires on every element boundary exit, causing isDragging to toggle rapidly. Use a dragenter/dragleave counter or restrict listeners to the drop zone, then remove the global dragleave binding.

🤖 Prompt for AI Agents
In apps/web/src/hooks/use-file-upload.ts around line 164, the
globalThis.addEventListener("dragleave", handleDragEnd) causes isDragging to
toggle on every element boundary; replace this global dragleave listener with
either a depth-aware approach (increment on dragenter, decrement on dragleave
and only end drag when counter reaches zero) or attach
dragenter/dragover/dragleave listeners directly to the drop-zone element (and
remove the global dragleave binding). Ensure the counter is initialized in the
hook, updated in dragenter/leave handlers, and use the counter reaching zero to
call handleDragEnd; also clean up the scoped listeners in the hook cleanup to
avoid leaks.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/web/src/components/agent/edit.tsx (1)

432-442: Consider if the useEffect is necessary.

The useEffect on Lines 440-442 syncs chatMode state with the URL parameter. However, since urlChatMode is computed from location.search which changes when the URL changes, you could directly use urlChatMode without maintaining separate state.

Consider simplifying:

- const [chatMode, setChatMode] = useState<"agent" | "decopilot">(urlChatMode);
-
- // Sync with URL changes
- useEffect(() => {
-   setChatMode(urlChatMode);
- }, [urlChatMode]);
+ const chatMode = urlChatMode;
+ const setChatMode = (mode: "agent" | "decopilot") => {
+   // Handle mode change by updating URL, which will trigger re-render
+ };

However, if you need setChatMode to be callable from child components that update the URL elsewhere, the current approach is fine. Just ensure the update flow is clear.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ffc280c and 85b662a.

📒 Files selected for processing (4)
  • apps/web/src/components/agent/edit.tsx (6 hunks)
  • apps/web/src/components/chat/chat-input.tsx (3 hunks)
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx (1 hunks)
  • apps/web/src/components/layout/project.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/components/integrations/tabs/connection-tabs.tsx
  • apps/web/src/components/chat/chat-input.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.{ts,tsx}: MCP tools must use Zod schemas for input and, when applicable, output validation
Register tools with server.registerTool providing description, inputSchema.shape, and optional outputSchema.shape
In every MCP tool handler, perform authorization checks first and then call context.resourceAccess.grant() before business logic
Name tools using the {RESOURCE}_{ACTION} pattern (e.g., AGENTS_CREATE, THREADS_LIST)
Group related tools into typed collections (e.g., GLOBAL_TOOLS, WORKSPACE_TOOLS) and export them as const
Always check workspace/team access before executing operations that touch workspace resources
Return proper authorization errors and handle forbidden operations explicitly

Prefer specific TypeScript types over any

**/*.{ts,tsx}: Write concise, maintainable, and technically accurate TypeScript code
Use functional and declarative programming patterns; avoid classes
Favor iteration and modularization to follow DRY and avoid code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Organize files so each contains only related content (components, subcomponents, helpers, static content, types)
Prefer interfaces over types for object shapes
Avoid enums; use maps (objects/records) instead
Use the function keyword for pure functions to benefit from hoisting and clarity
Ensure dependency arrays use stable references; do not inline new objects/arrays/functions
Memoize options/objects used in hooks (e.g., useMemo for options passed to useMemo/useCallback)
Favor named exports for functions

Files:

  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.tsx: Use the shared KEYS object to construct consistent React Query keys
Use useSuspenseQuery for critical data fetching hooks
Implement optimistic updates for mutations and provide rollback on error via onMutate/onError
After successful mutations, update relevant caches with setQueryData (e.g., entity detail and list keys)
Leverage React Query’s built-in request deduplication instead of manual throttling
Use parallel queries where appropriate to reduce total load time

**/*.tsx: Use functional React components typed with TypeScript interfaces
Prefer using existing UI components from packages/ui over custom duplicates
Always use design system components from @deco/ui in UI code instead of hand-rolled equivalents
Memoize expensive computations with useMemo (e.g., filtering/sorting)
Memoize objects/arrays used in renders to keep stable references (useMemo)
Use useDeferredValue to keep search inputs responsive during heavy filtering
Follow MCP Tool data-access patterns (e.g., useAgents, useIntegrations) with proper loading/error states
Prefer react-hook-form with schema validation (e.g., zod) over manual useState for forms
Avoid prop drilling for forms by using a form context/provider
Adhere to Single Responsibility Principle by splitting large components into focused subcomponents
Design for composability and reusability of small UI components (e.g., Avatar variants)
Provide consistent loading and error states for data-driven components (e.g., Spinner, ErrorMessage, EmptyState)
Extract complex inline logic from JSX (avoid IIFEs) into small components/functions

Files:

  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

apps/web/**/*.{js,jsx,ts,tsx}: Use each feature flag in as few places as possible; if a flag must appear at multiple callsites, explicitly flag this for careful developer review
Gate any flag-dependent code behind checks that verify the flag’s values are valid and expected
If a custom person or event property is referenced in two or more files or at two or more callsites in the same file, centralize the keys in an enum (TS) or const object (JS)

Files:

  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

In TypeScript, store feature flag names in an enum with members written UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention

Files:

  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
apps/web/**

📄 CodeRabbit inference engine (AGENTS.md)

Place the Vite/React web client in apps/web

Files:

  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Biome formatting: use two-space indentation and double quotes
Keep imports sorted
Name hooks and utility functions using camelCase

Files:

  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components and classes using PascalCase

Files:

  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
{apps/web,packages}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Tailwind design tokens consistent with the design system

Files:

  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
🧬 Code graph analysis (2)
apps/web/src/components/layout/project.tsx (3)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/common/avatar/agent.tsx (1)
  • AgentAvatar (21-71)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (282-338)
apps/web/src/components/agent/edit.tsx (8)
apps/web/src/components/agent/provider.tsx (2)
  • useAgent (600-604)
  • AgentProvider (151-597)
apps/web/src/components/chat/chat-input.tsx (1)
  • ChatInput (20-214)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/decopilot/thread-context.tsx (1)
  • useDecopilotThread (100-108)
apps/web/src/components/decopilot/use-app-additional-tools.ts (1)
  • useAppAdditionalTools (4-24)
apps/web/src/components/decopilot/context.tsx (1)
  • useDecopilotContext (26-29)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (282-338)
packages/ui/src/hooks/use-mobile.ts (1)
  • useIsMobile (7-21)
🔇 Additional comments (11)
apps/web/src/components/layout/project.tsx (4)

1-36: LGTM!

The new imports are properly organized and support the agent chat mode switching functionality.


218-239: LGTM!

The update to use AgentAvatar provides visual consistency with the agent chat mode switch and properly handles the decopilot avatar with a fallback image.


241-257: Regex correctly matches agent detail pages The pattern /\/agent\/[^\/]+\/[^\/]+$/ aligns with the route definition agent/:id/:threadId in apps/web/src/main.tsx:430, so no change is needed.

Likely an incorrect or invalid review comment.


160-216: AgentChatModeSwitch agentId guard sufficient; confirm error boundary.

  • AgentChatModeSwitch only renders on agent detail pages (isAgentDetailPage), so agentId from useParams() will always be defined.
  • Verify that this component is wrapped in an ErrorBoundary (or global boundary) to catch any errors from the Suspense query (useAgentData).
apps/web/src/components/agent/edit.tsx (7)

27-79: LGTM!

The PreviewContext structure is well-designed, providing clear separation of concerns for mobile preview management and chat mode state. The context hook properly throws an error when used outside the provider.


104-159: LGTM! Good UX consideration.

The use of absolute positioning for the thread controls (Lines 132-148) is a smart approach to prevent layout shifts when toggling between empty and non-empty states. The conditional rendering based on chatMode properly hides decopilot-inappropriate controls.


218-278: LGTM!

The mobile-friendly floating preview toggle button with fixed positioning (bottom-6 right-6 z-50) provides good UX without interfering with the main content.


313-322: LGTM!

The memoization correctly depends on chatMode and editingAgent, and the early return prevents unnecessary rule generation when not in decopilot mode.


392-416: LGTM!

Clean separation of mobile (single-view toggle) and desktop (split resizable panels) layouts. The height calculations (h-[calc(100vh-48px)]) are consistent across both layouts.


458-489: LGTM!

The provider nesting structure is clean and logical: DecopilotLayoutPreviewContextAgentProviderResponsiveLayout. Document metadata is properly configured with agent information.


280-390: AgentProvider cleans up subscriptions on unmount
The useEffect for onRulesUpdated returns a cleanup function, so both providers remain mounted by design to preserve state without leaking subscriptions or resources.

- Fix import formatting in chat-input.tsx
- Update button title and icon to reflect only integrations
- Remove unnecessary wrapper div around rightNode
- Fix nested DecopilotLayout by using DecopilotProvider in ChatWithProvider
- Fix thread ID mismatch for decopilot mode
- Add guard for missing agentId before calling useAgentData
- Wrap TopbarControls in Suspense boundary
- Fix variable declaration order to use threadState after it's declared
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (4)
apps/web/src/components/layout/project.tsx (1)

169-173: Good guard before useAgentData avoids invalid suspense fetches

Early-return on missing agentId prevents calling useAgentData with an empty string. This addresses the prior concern.

apps/web/src/components/layout/topbar.tsx (1)

58-60: Wrapping TopbarControls in Suspense is correct

TopbarControls can suspend via useSuspenseQuery; local Suspense prevents header-level unhandled suspension. LGTM.

Based on learnings

apps/web/src/components/chat/context-resources.tsx (1)

211-214: Updated button title/icon match functionality

Title and icon now reflect “Add integrations.” Looks good.

apps/web/src/components/agent/edit.tsx (1)

297-387: Decopilot thread id is now correctly applied

effectiveDecopilotThreadId is used for both key and threadId, ensuring backend thread switches match remounts. Nice fix.

🧹 Nitpick comments (6)
apps/web/src/components/layout/project.tsx (3)

208-217: Label clarity: prefer “Decopilot” over generic “Chat”

Improves mode discoverability and parity with “Agent”.

Apply:

-        Chat
+        Decopilot

230-241: Consistent naming: “Decopilot” matches the avatar and mode

Align the button text with the decopilot agent.

Apply:

-      Chat
+      Decopilot

245-261: Route check with regex is brittle; use useMatch for route-shape safety

useMatch handles trailing slashes and future path changes better than a regex.

Example:

-import { useLocation } from "react-router";
+import { useLocation, useMatch } from "react-router";
@@
-  const isAgentDetailPage = location.pathname.match(/\/agent\/[^\/]+\/[^\/]+$/);
+  const isAgentDetailPage = Boolean(
+    useMatch("/:org/:project/agent/:id/:threadId"),
+  );

As per coding guidelines

apps/web/src/components/chat/context-resources.tsx (2)

286-296: Avoid awaiting a non-Promise; make onRemove async-capable or drop await

onRemove is typed as () => void, but you await it. Either allow Promise in the type or remove async/await to avoid confusion.

Apply:

 interface IntegrationResourceItemProps {
   integration: Integration;
   enabledTools: string[];
   totalTools: number;
   onRemove: () => void;
   onToggleTool: (toolName: string, isEnabled: boolean) => void;
 }

Option A (prefer): make onRemove async-capable.

 interface IntegrationResourceItemProps {
@@
-  onRemove: () => void;
+  onRemove: () => Promise<void> | void;
 }
@@
-      <Button
+      <Button
         type="button"
         variant="ghost"
         size="icon"
-        onClick={async () => {
-          setIsRemoving(true);
-          try {
-            await onRemove();
-          } finally {
-            setIsRemoving(false);
-          }
-        }}
+        onClick={() => {
+          setIsRemoving(true);
+          Promise.resolve(onRemove()).finally(() => setIsRemoving(false));
+        }}

Option B: drop async/await entirely if removal is always sync.

Also applies to: 367-385


440-444: Accessibility: add alt text to file preview images

Use file name as alt for better a11y.

Apply:

-            {file.type.startsWith("image/") && url ? (
-              <img src={url} className="h-full w-full object-cover" />
+            {file.type.startsWith("image/") && url ? (
+              <img src={url} alt={file.name} className="h-full w-full object-cover" />
apps/web/src/components/agent/edit.tsx (1)

291-326: Redundant agent fetch in ChatWithProvider; reuse agent from FormProvider

FormProvider already loads agent via useAgentData; ChatWithProvider does it again. Pass down the loaded agent (or just the name) to build decopilot rules and avoid an extra suspense query.

As per coding guidelines

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85b662a and 9957282.

📒 Files selected for processing (4)
  • apps/web/src/components/agent/edit.tsx (6 hunks)
  • apps/web/src/components/chat/context-resources.tsx (3 hunks)
  • apps/web/src/components/layout/project.tsx (5 hunks)
  • apps/web/src/components/layout/topbar.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.{ts,tsx}: MCP tools must use Zod schemas for input and, when applicable, output validation
Register tools with server.registerTool providing description, inputSchema.shape, and optional outputSchema.shape
In every MCP tool handler, perform authorization checks first and then call context.resourceAccess.grant() before business logic
Name tools using the {RESOURCE}_{ACTION} pattern (e.g., AGENTS_CREATE, THREADS_LIST)
Group related tools into typed collections (e.g., GLOBAL_TOOLS, WORKSPACE_TOOLS) and export them as const
Always check workspace/team access before executing operations that touch workspace resources
Return proper authorization errors and handle forbidden operations explicitly

Prefer specific TypeScript types over any

**/*.{ts,tsx}: Write concise, maintainable, and technically accurate TypeScript code
Use functional and declarative programming patterns; avoid classes
Favor iteration and modularization to follow DRY and avoid code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Organize files so each contains only related content (components, subcomponents, helpers, static content, types)
Prefer interfaces over types for object shapes
Avoid enums; use maps (objects/records) instead
Use the function keyword for pure functions to benefit from hoisting and clarity
Ensure dependency arrays use stable references; do not inline new objects/arrays/functions
Memoize options/objects used in hooks (e.g., useMemo for options passed to useMemo/useCallback)
Favor named exports for functions

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.tsx: Use the shared KEYS object to construct consistent React Query keys
Use useSuspenseQuery for critical data fetching hooks
Implement optimistic updates for mutations and provide rollback on error via onMutate/onError
After successful mutations, update relevant caches with setQueryData (e.g., entity detail and list keys)
Leverage React Query’s built-in request deduplication instead of manual throttling
Use parallel queries where appropriate to reduce total load time

**/*.tsx: Use functional React components typed with TypeScript interfaces
Prefer using existing UI components from packages/ui over custom duplicates
Always use design system components from @deco/ui in UI code instead of hand-rolled equivalents
Memoize expensive computations with useMemo (e.g., filtering/sorting)
Memoize objects/arrays used in renders to keep stable references (useMemo)
Use useDeferredValue to keep search inputs responsive during heavy filtering
Follow MCP Tool data-access patterns (e.g., useAgents, useIntegrations) with proper loading/error states
Prefer react-hook-form with schema validation (e.g., zod) over manual useState for forms
Avoid prop drilling for forms by using a form context/provider
Adhere to Single Responsibility Principle by splitting large components into focused subcomponents
Design for composability and reusability of small UI components (e.g., Avatar variants)
Provide consistent loading and error states for data-driven components (e.g., Spinner, ErrorMessage, EmptyState)
Extract complex inline logic from JSX (avoid IIFEs) into small components/functions

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

apps/web/**/*.{js,jsx,ts,tsx}: Use each feature flag in as few places as possible; if a flag must appear at multiple callsites, explicitly flag this for careful developer review
Gate any flag-dependent code behind checks that verify the flag’s values are valid and expected
If a custom person or event property is referenced in two or more files or at two or more callsites in the same file, centralize the keys in an enum (TS) or const object (JS)

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

In TypeScript, store feature flag names in an enum with members written UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
apps/web/**

📄 CodeRabbit inference engine (AGENTS.md)

Place the Vite/React web client in apps/web

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Biome formatting: use two-space indentation and double quotes
Keep imports sorted
Name hooks and utility functions using camelCase

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components and classes using PascalCase

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
{apps/web,packages}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Tailwind design tokens consistent with the design system

Files:

  • apps/web/src/components/chat/context-resources.tsx
  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/layout/project.tsx
  • apps/web/src/components/agent/edit.tsx
🧠 Learnings (1)
📚 Learning: 2025-09-02T13:56:59.909Z
Learnt from: CR
PR: deco-cx/chat#0
File: .cursor/rules/data-flow.mdc:0-0
Timestamp: 2025-09-02T13:56:59.909Z
Learning: Applies to **/*.tsx : Use useSuspenseQuery for critical data fetching hooks

Applied to files:

  • apps/web/src/components/layout/topbar.tsx
🧬 Code graph analysis (4)
apps/web/src/components/chat/context-resources.tsx (1)
apps/web/src/components/integrations/select-connection-dialog.tsx (1)
  • SelectConnectionDialog (860-893)
apps/web/src/components/layout/topbar.tsx (1)
apps/web/src/components/layout/project.tsx (1)
  • TopbarControls (245-261)
apps/web/src/components/layout/project.tsx (3)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/common/avatar/agent.tsx (1)
  • AgentAvatar (21-71)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (282-338)
apps/web/src/components/agent/edit.tsx (6)
apps/web/src/components/agent/provider.tsx (2)
  • useAgent (600-604)
  • AgentProvider (151-597)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/decopilot/thread-context.tsx (1)
  • useDecopilotThread (100-108)
apps/web/src/components/decopilot/use-app-additional-tools.ts (1)
  • useAppAdditionalTools (4-24)
apps/web/src/components/decopilot/context.tsx (2)
  • useDecopilotContext (26-29)
  • DecopilotProvider (18-24)
packages/ui/src/hooks/use-mobile.ts (1)
  • useIsMobile (7-21)
🔇 Additional comments (1)
apps/web/src/components/agent/edit.tsx (1)

475-493: Ignore nested DecopilotLayout suggestion No higher-level wrapper provides DecopilotLayout; each route component must include it, so this wrapper is required.

Likely an incorrect or invalid review comment.

Comment thread apps/web/src/components/agent/edit.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9957282 and a4e2c6e.

📒 Files selected for processing (1)
  • apps/web/src/components/agent/edit.tsx (6 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.{ts,tsx}: MCP tools must use Zod schemas for input and, when applicable, output validation
Register tools with server.registerTool providing description, inputSchema.shape, and optional outputSchema.shape
In every MCP tool handler, perform authorization checks first and then call context.resourceAccess.grant() before business logic
Name tools using the {RESOURCE}_{ACTION} pattern (e.g., AGENTS_CREATE, THREADS_LIST)
Group related tools into typed collections (e.g., GLOBAL_TOOLS, WORKSPACE_TOOLS) and export them as const
Always check workspace/team access before executing operations that touch workspace resources
Return proper authorization errors and handle forbidden operations explicitly

Prefer specific TypeScript types over any

**/*.{ts,tsx}: Write concise, maintainable, and technically accurate TypeScript code
Use functional and declarative programming patterns; avoid classes
Favor iteration and modularization to follow DRY and avoid code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Organize files so each contains only related content (components, subcomponents, helpers, static content, types)
Prefer interfaces over types for object shapes
Avoid enums; use maps (objects/records) instead
Use the function keyword for pure functions to benefit from hoisting and clarity
Ensure dependency arrays use stable references; do not inline new objects/arrays/functions
Memoize options/objects used in hooks (e.g., useMemo for options passed to useMemo/useCallback)
Favor named exports for functions

Files:

  • apps/web/src/components/agent/edit.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.tsx: Use the shared KEYS object to construct consistent React Query keys
Use useSuspenseQuery for critical data fetching hooks
Implement optimistic updates for mutations and provide rollback on error via onMutate/onError
After successful mutations, update relevant caches with setQueryData (e.g., entity detail and list keys)
Leverage React Query’s built-in request deduplication instead of manual throttling
Use parallel queries where appropriate to reduce total load time

**/*.tsx: Use functional React components typed with TypeScript interfaces
Prefer using existing UI components from packages/ui over custom duplicates
Always use design system components from @deco/ui in UI code instead of hand-rolled equivalents
Memoize expensive computations with useMemo (e.g., filtering/sorting)
Memoize objects/arrays used in renders to keep stable references (useMemo)
Use useDeferredValue to keep search inputs responsive during heavy filtering
Follow MCP Tool data-access patterns (e.g., useAgents, useIntegrations) with proper loading/error states
Prefer react-hook-form with schema validation (e.g., zod) over manual useState for forms
Avoid prop drilling for forms by using a form context/provider
Adhere to Single Responsibility Principle by splitting large components into focused subcomponents
Design for composability and reusability of small UI components (e.g., Avatar variants)
Provide consistent loading and error states for data-driven components (e.g., Spinner, ErrorMessage, EmptyState)
Extract complex inline logic from JSX (avoid IIFEs) into small components/functions

Files:

  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

apps/web/**/*.{js,jsx,ts,tsx}: Use each feature flag in as few places as possible; if a flag must appear at multiple callsites, explicitly flag this for careful developer review
Gate any flag-dependent code behind checks that verify the flag’s values are valid and expected
If a custom person or event property is referenced in two or more files or at two or more callsites in the same file, centralize the keys in an enum (TS) or const object (JS)

Files:

  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

In TypeScript, store feature flag names in an enum with members written UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention

Files:

  • apps/web/src/components/agent/edit.tsx
apps/web/**

📄 CodeRabbit inference engine (AGENTS.md)

Place the Vite/React web client in apps/web

Files:

  • apps/web/src/components/agent/edit.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Biome formatting: use two-space indentation and double quotes
Keep imports sorted
Name hooks and utility functions using camelCase

Files:

  • apps/web/src/components/agent/edit.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components and classes using PascalCase

Files:

  • apps/web/src/components/agent/edit.tsx
{apps/web,packages}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Tailwind design tokens consistent with the design system

Files:

  • apps/web/src/components/agent/edit.tsx
🧬 Code graph analysis (1)
apps/web/src/components/agent/edit.tsx (9)
apps/web/src/components/agent/provider.tsx (2)
  • useAgent (600-604)
  • AgentProvider (151-597)
apps/web/src/components/agents/hooks.ts (1)
  • useFocusChat (13-45)
apps/web/src/components/chat/chat-input.tsx (1)
  • ChatInput (20-214)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/decopilot/thread-context.tsx (1)
  • useDecopilotThread (100-108)
apps/web/src/components/decopilot/use-app-additional-tools.ts (1)
  • useAppAdditionalTools (4-24)
apps/web/src/components/decopilot/context.tsx (1)
  • useDecopilotContext (26-29)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (282-338)
packages/ui/src/hooks/use-mobile.ts (1)
  • useIsMobile (7-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages

Comment thread apps/web/src/components/agent/edit.tsx Outdated
@guitavano
Copy link
Copy Markdown
Contributor

I expected the name would be updated

Screen.Recording.2025-10-14.at.08.57.44.mov

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4e2c6e and 4148735.

📒 Files selected for processing (2)
  • apps/web/src/components/agent/edit.tsx (7 hunks)
  • apps/web/src/components/layout/topbar.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.{ts,tsx}: MCP tools must use Zod schemas for input and, when applicable, output validation
Register tools with server.registerTool providing description, inputSchema.shape, and optional outputSchema.shape
In every MCP tool handler, perform authorization checks first and then call context.resourceAccess.grant() before business logic
Name tools using the {RESOURCE}_{ACTION} pattern (e.g., AGENTS_CREATE, THREADS_LIST)
Group related tools into typed collections (e.g., GLOBAL_TOOLS, WORKSPACE_TOOLS) and export them as const
Always check workspace/team access before executing operations that touch workspace resources
Return proper authorization errors and handle forbidden operations explicitly

Prefer specific TypeScript types over any

**/*.{ts,tsx}: Write concise, maintainable, and technically accurate TypeScript code
Use functional and declarative programming patterns; avoid classes
Favor iteration and modularization to follow DRY and avoid code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Organize files so each contains only related content (components, subcomponents, helpers, static content, types)
Prefer interfaces over types for object shapes
Avoid enums; use maps (objects/records) instead
Use the function keyword for pure functions to benefit from hoisting and clarity
Ensure dependency arrays use stable references; do not inline new objects/arrays/functions
Memoize options/objects used in hooks (e.g., useMemo for options passed to useMemo/useCallback)
Favor named exports for functions

Files:

  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/agent/edit.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.tsx: Use the shared KEYS object to construct consistent React Query keys
Use useSuspenseQuery for critical data fetching hooks
Implement optimistic updates for mutations and provide rollback on error via onMutate/onError
After successful mutations, update relevant caches with setQueryData (e.g., entity detail and list keys)
Leverage React Query’s built-in request deduplication instead of manual throttling
Use parallel queries where appropriate to reduce total load time

**/*.tsx: Use functional React components typed with TypeScript interfaces
Prefer using existing UI components from packages/ui over custom duplicates
Always use design system components from @deco/ui in UI code instead of hand-rolled equivalents
Memoize expensive computations with useMemo (e.g., filtering/sorting)
Memoize objects/arrays used in renders to keep stable references (useMemo)
Use useDeferredValue to keep search inputs responsive during heavy filtering
Follow MCP Tool data-access patterns (e.g., useAgents, useIntegrations) with proper loading/error states
Prefer react-hook-form with schema validation (e.g., zod) over manual useState for forms
Avoid prop drilling for forms by using a form context/provider
Adhere to Single Responsibility Principle by splitting large components into focused subcomponents
Design for composability and reusability of small UI components (e.g., Avatar variants)
Provide consistent loading and error states for data-driven components (e.g., Spinner, ErrorMessage, EmptyState)
Extract complex inline logic from JSX (avoid IIFEs) into small components/functions

Files:

  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

apps/web/**/*.{js,jsx,ts,tsx}: Use each feature flag in as few places as possible; if a flag must appear at multiple callsites, explicitly flag this for careful developer review
Gate any flag-dependent code behind checks that verify the flag’s values are valid and expected
If a custom person or event property is referenced in two or more files or at two or more callsites in the same file, centralize the keys in an enum (TS) or const object (JS)

Files:

  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

In TypeScript, store feature flag names in an enum with members written UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention

Files:

  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/agent/edit.tsx
apps/web/**

📄 CodeRabbit inference engine (AGENTS.md)

Place the Vite/React web client in apps/web

Files:

  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/agent/edit.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Biome formatting: use two-space indentation and double quotes
Keep imports sorted
Name hooks and utility functions using camelCase

Files:

  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/agent/edit.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components and classes using PascalCase

Files:

  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/agent/edit.tsx
{apps/web,packages}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Tailwind design tokens consistent with the design system

Files:

  • apps/web/src/components/layout/topbar.tsx
  • apps/web/src/components/agent/edit.tsx
🧬 Code graph analysis (2)
apps/web/src/components/layout/topbar.tsx (1)
apps/web/src/components/layout/project.tsx (1)
  • TopbarControls (245-261)
apps/web/src/components/agent/edit.tsx (9)
apps/web/src/components/agent/provider.tsx (2)
  • useAgent (664-668)
  • AgentProvider (151-661)
apps/web/src/components/agents/hooks.ts (1)
  • useFocusChat (13-45)
apps/web/src/components/chat/chat-messages.tsx (1)
  • ChatMessages (35-155)
apps/web/src/components/chat/chat-input.tsx (1)
  • ChatInput (20-214)
apps/web/src/components/decopilot/thread-context.tsx (1)
  • useDecopilotThread (100-108)
apps/web/src/components/decopilot/use-app-additional-tools.ts (1)
  • useAppAdditionalTools (4-24)
apps/web/src/components/decopilot/context.tsx (1)
  • useDecopilotContext (26-29)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (286-342)
packages/ui/src/hooks/use-mobile.ts (1)
  • useIsMobile (7-21)
🪛 GitHub Actions: Tests
apps/web/src/components/agent/edit.tsx

[error] 431-431: Cannot find name 'useRef'. (TS2304)

🔇 Additional comments (5)
apps/web/src/components/layout/topbar.tsx (1)

11-11: LGTM - Suspense boundary properly addresses component suspension.

The Suspense boundary correctly handles the fact that TopbarControls can suspend (via AgentChatModeSwitch's useSuspenseQuery). The fallback={null} provides a clean user experience during loading.

Also applies to: 17-17, 96-98

apps/web/src/components/agent/edit.tsx (4)

62-81: Well-designed PreviewContext for mobile-aware UI state.

The context cleanly encapsulates mobile preview visibility, chat mode, and mode switching. The hook provides proper error handling when used outside the provider.


106-161: UnifiedChat consolidates agent and decopilot chat UIs effectively.

The conditional rendering based on chatMode keeps the UI consistent while hiding mode-specific controls (threads, new thread button) from decopilot mode. The absolute positioning of buttons prevents layout shift.

Minor note: The pr-24 padding (line 126) should accommodate the two buttons (New Thread + ThreadsButton) at roughly 8rem; verify this provides sufficient space on narrow viewports.


395-419: ResponsiveLayout cleanly adapts to mobile vs desktop contexts.

The mobile stacked layout and desktop resizable panels provide a solid responsive foundation. Toggling between config and chat on mobile via showPreview is straightforward.


469-486: Mobile detection and chat mode state management is well-structured.

The URL-synced chatMode state (lines 476-486) ensures deep-links work correctly, and the useEffect keeps local state in sync with URL changes. The mobile detection hook provides reactive layout switching.

Comment thread apps/web/src/components/agent/edit.tsx
Comment thread apps/web/src/components/agent/edit.tsx Outdated
Copy link
Copy Markdown
Contributor

@lucis lucis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

How was this Agent|Chat built?

image

I'd love the PR even more if this was just "a view that is pinned at the top" from this current app (in this case, the Agent Editor app).

It's impossible to overlook that a button with Agent | Chat looks confusing.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4148735 and 03a495d.

📒 Files selected for processing (1)
  • apps/web/src/components/agent/edit.tsx (7 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.{ts,tsx}: MCP tools must use Zod schemas for input and, when applicable, output validation
Register tools with server.registerTool providing description, inputSchema.shape, and optional outputSchema.shape
In every MCP tool handler, perform authorization checks first and then call context.resourceAccess.grant() before business logic
Name tools using the {RESOURCE}_{ACTION} pattern (e.g., AGENTS_CREATE, THREADS_LIST)
Group related tools into typed collections (e.g., GLOBAL_TOOLS, WORKSPACE_TOOLS) and export them as const
Always check workspace/team access before executing operations that touch workspace resources
Return proper authorization errors and handle forbidden operations explicitly

Prefer specific TypeScript types over any

**/*.{ts,tsx}: Write concise, maintainable, and technically accurate TypeScript code
Use functional and declarative programming patterns; avoid classes
Favor iteration and modularization to follow DRY and avoid code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Organize files so each contains only related content (components, subcomponents, helpers, static content, types)
Prefer interfaces over types for object shapes
Avoid enums; use maps (objects/records) instead
Use the function keyword for pure functions to benefit from hoisting and clarity
Ensure dependency arrays use stable references; do not inline new objects/arrays/functions
Memoize options/objects used in hooks (e.g., useMemo for options passed to useMemo/useCallback)
Favor named exports for functions

Files:

  • apps/web/src/components/agent/edit.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.tsx: Use the shared KEYS object to construct consistent React Query keys
Use useSuspenseQuery for critical data fetching hooks
Implement optimistic updates for mutations and provide rollback on error via onMutate/onError
After successful mutations, update relevant caches with setQueryData (e.g., entity detail and list keys)
Leverage React Query’s built-in request deduplication instead of manual throttling
Use parallel queries where appropriate to reduce total load time

**/*.tsx: Use functional React components typed with TypeScript interfaces
Prefer using existing UI components from packages/ui over custom duplicates
Always use design system components from @deco/ui in UI code instead of hand-rolled equivalents
Memoize expensive computations with useMemo (e.g., filtering/sorting)
Memoize objects/arrays used in renders to keep stable references (useMemo)
Use useDeferredValue to keep search inputs responsive during heavy filtering
Follow MCP Tool data-access patterns (e.g., useAgents, useIntegrations) with proper loading/error states
Prefer react-hook-form with schema validation (e.g., zod) over manual useState for forms
Avoid prop drilling for forms by using a form context/provider
Adhere to Single Responsibility Principle by splitting large components into focused subcomponents
Design for composability and reusability of small UI components (e.g., Avatar variants)
Provide consistent loading and error states for data-driven components (e.g., Spinner, ErrorMessage, EmptyState)
Extract complex inline logic from JSX (avoid IIFEs) into small components/functions

Files:

  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

apps/web/**/*.{js,jsx,ts,tsx}: Use each feature flag in as few places as possible; if a flag must appear at multiple callsites, explicitly flag this for careful developer review
Gate any flag-dependent code behind checks that verify the flag’s values are valid and expected
If a custom person or event property is referenced in two or more files or at two or more callsites in the same file, centralize the keys in an enum (TS) or const object (JS)

Files:

  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

In TypeScript, store feature flag names in an enum with members written UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention

Files:

  • apps/web/src/components/agent/edit.tsx
apps/web/**

📄 CodeRabbit inference engine (AGENTS.md)

Place the Vite/React web client in apps/web

Files:

  • apps/web/src/components/agent/edit.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Biome formatting: use two-space indentation and double quotes
Keep imports sorted
Name hooks and utility functions using camelCase

Files:

  • apps/web/src/components/agent/edit.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components and classes using PascalCase

Files:

  • apps/web/src/components/agent/edit.tsx
{apps/web,packages}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Tailwind design tokens consistent with the design system

Files:

  • apps/web/src/components/agent/edit.tsx
🧬 Code graph analysis (1)
apps/web/src/components/agent/edit.tsx (9)
apps/web/src/components/agent/provider.tsx (2)
  • useAgent (664-668)
  • AgentProvider (151-661)
apps/web/src/components/agents/hooks.ts (1)
  • useFocusChat (13-45)
apps/web/src/components/chat/chat-input.tsx (1)
  • ChatInput (20-214)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/decopilot/thread-context.tsx (1)
  • useDecopilotThread (100-108)
apps/web/src/components/decopilot/use-app-additional-tools.ts (1)
  • useAppAdditionalTools (4-24)
apps/web/src/components/decopilot/context.tsx (1)
  • useDecopilotContext (26-29)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (286-342)
packages/ui/src/hooks/use-mobile.ts (1)
  • useIsMobile (7-21)

Comment thread apps/web/src/components/agent/edit.tsx Outdated
@abdulhdr1 abdulhdr1 merged commit fa7109d into main Oct 15, 2025
1 check passed
@abdulhdr1 abdulhdr1 deleted the abdul/13-10-25-ux-bugfixes branch October 15, 2025 13:07
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
apps/web/src/components/agent/edit.tsx (4)

345-395: Consider unmounting inactive provider for better performance.

Both agent and decopilot providers are always mounted (lines 350-365 and 368-393), with visibility toggled via className. While this preserves state when switching modes, it means both providers are running their subscriptions, effects, and consuming memory even when hidden.

For better performance, consider unmounting the inactive provider and restoring its state from React Query cache or local state when switching back. The trade-off is increased complexity versus the current simpler approach.

As per coding guidelines, memoize and modularize to follow DRY principles.


320-341: Consider combining related memoization for minor performance gain.

The decopilotContextValue, allAdditionalTools, and allRules computations (lines 320-341) could be combined into a single useMemo hook since they all depend on similar conditions and are used together.

Example refactor:

-  const decopilotContextValue = useMemo(() => {
-    if (chatMode !== "decopilot" || !editingAgent) return {};
-    // ... rules creation
-    return { rules };
-  }, [chatMode, editingAgent]);
-
-  const allAdditionalTools = chatMode === "decopilot"
-    ? { ...appAdditionalTools, ...contextTools }
-    : undefined;
-
-  const allRules = chatMode === "decopilot"
-    ? [...(decopilotContextValue.rules || []), ...(contextRules || [])]
-    : undefined;
+  const decopilotConfig = useMemo(() => {
+    if (chatMode !== "decopilot") return { contextValue: {}, tools: undefined, rules: undefined };
+    
+    const rules = !editingAgent ? [] : [
+      `You are helping with agent editing and configuration...`,
+      `When working with this agent (${editingAgent.name})...`,
+    ];
+    
+    return {
+      contextValue: { rules },
+      tools: { ...appAdditionalTools, ...contextTools },
+      rules: [...rules, ...(contextRules || [])],
+    };
+  }, [chatMode, editingAgent, appAdditionalTools, contextTools, contextRules]);

343-343: Defensive null check is unnecessary.

The if (!chatAgentId) return null; check at line 343 is defensive but unnecessary. The chatAgentId is derived from either WELL_KNOWN_AGENTS.decopilotAgent.id (always defined) or agentId. The parent Page component (lines 563-565) already throws an error if !agentId, so this condition can never be true.

Consider removing the check or adding a comment explaining it's defensive:

+ // Defensive check (should never happen due to parent validation)
  if (!chatAgentId) return null;

489-499: Sync chatMode updates back to the URL
Wrap the existing setChatMode in a useCallback that also updates the chat search param via React Router’s navigate (or useSearchParams), then pass this wrapped setter into PreviewContext.Provider so state and URL stay in sync.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ff8790 and a4013af.

📒 Files selected for processing (1)
  • apps/web/src/components/agent/edit.tsx (8 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.{ts,tsx}: MCP tools must use Zod schemas for input and, when applicable, output validation
Register tools with server.registerTool providing description, inputSchema.shape, and optional outputSchema.shape
In every MCP tool handler, perform authorization checks first and then call context.resourceAccess.grant() before business logic
Name tools using the {RESOURCE}_{ACTION} pattern (e.g., AGENTS_CREATE, THREADS_LIST)
Group related tools into typed collections (e.g., GLOBAL_TOOLS, WORKSPACE_TOOLS) and export them as const
Always check workspace/team access before executing operations that touch workspace resources
Return proper authorization errors and handle forbidden operations explicitly

Prefer specific TypeScript types over any

**/*.{ts,tsx}: Write concise, maintainable, and technically accurate TypeScript code
Use functional and declarative programming patterns; avoid classes
Favor iteration and modularization to follow DRY and avoid code duplication
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Organize files so each contains only related content (components, subcomponents, helpers, static content, types)
Prefer interfaces over types for object shapes
Avoid enums; use maps (objects/records) instead
Use the function keyword for pure functions to benefit from hoisting and clarity
Ensure dependency arrays use stable references; do not inline new objects/arrays/functions
Memoize options/objects used in hooks (e.g., useMemo for options passed to useMemo/useCallback)
Favor named exports for functions

Files:

  • apps/web/src/components/agent/edit.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/data-flow.mdc)

**/*.tsx: Use the shared KEYS object to construct consistent React Query keys
Use useSuspenseQuery for critical data fetching hooks
Implement optimistic updates for mutations and provide rollback on error via onMutate/onError
After successful mutations, update relevant caches with setQueryData (e.g., entity detail and list keys)
Leverage React Query’s built-in request deduplication instead of manual throttling
Use parallel queries where appropriate to reduce total load time

**/*.tsx: Use functional React components typed with TypeScript interfaces
Prefer using existing UI components from packages/ui over custom duplicates
Always use design system components from @deco/ui in UI code instead of hand-rolled equivalents
Memoize expensive computations with useMemo (e.g., filtering/sorting)
Memoize objects/arrays used in renders to keep stable references (useMemo)
Use useDeferredValue to keep search inputs responsive during heavy filtering
Follow MCP Tool data-access patterns (e.g., useAgents, useIntegrations) with proper loading/error states
Prefer react-hook-form with schema validation (e.g., zod) over manual useState for forms
Avoid prop drilling for forms by using a form context/provider
Adhere to Single Responsibility Principle by splitting large components into focused subcomponents
Design for composability and reusability of small UI components (e.g., Avatar variants)
Provide consistent loading and error states for data-driven components (e.g., Spinner, ErrorMessage, EmptyState)
Extract complex inline logic from JSX (avoid IIFEs) into small components/functions

Files:

  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

apps/web/**/*.{js,jsx,ts,tsx}: Use each feature flag in as few places as possible; if a flag must appear at multiple callsites, explicitly flag this for careful developer review
Gate any flag-dependent code behind checks that verify the flag’s values are valid and expected
If a custom person or event property is referenced in two or more files or at two or more callsites in the same file, centralize the keys in an enum (TS) or const object (JS)

Files:

  • apps/web/src/components/agent/edit.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/.cursor/rules/posthog-integration.mdc)

In TypeScript, store feature flag names in an enum with members written UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention

Files:

  • apps/web/src/components/agent/edit.tsx
apps/web/**

📄 CodeRabbit inference engine (AGENTS.md)

Place the Vite/React web client in apps/web

Files:

  • apps/web/src/components/agent/edit.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Biome formatting: use two-space indentation and double quotes
Keep imports sorted
Name hooks and utility functions using camelCase

Files:

  • apps/web/src/components/agent/edit.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Name React components and classes using PascalCase

Files:

  • apps/web/src/components/agent/edit.tsx
{apps/web,packages}/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Tailwind design tokens consistent with the design system

Files:

  • apps/web/src/components/agent/edit.tsx
🧬 Code graph analysis (1)
apps/web/src/components/agent/edit.tsx (10)
apps/web/src/components/agent/provider.tsx (2)
  • useAgent (663-667)
  • AgentProvider (151-660)
apps/web/src/components/agents/hooks.ts (1)
  • useFocusChat (13-45)
apps/web/src/components/chat/chat-messages.tsx (1)
  • ChatMessages (35-155)
apps/web/src/components/chat/chat-input.tsx (1)
  • ChatInput (20-214)
packages/sdk/src/hooks/agent.ts (1)
  • useAgentData (107-120)
apps/web/src/components/decopilot/thread-context.tsx (1)
  • useDecopilotThread (100-108)
apps/web/src/components/decopilot/use-app-additional-tools.ts (1)
  • useAppAdditionalTools (4-24)
apps/web/src/components/decopilot/context.tsx (1)
  • useDecopilotContext (26-29)
packages/sdk/src/constants.ts (1)
  • WELL_KNOWN_AGENTS (286-342)
packages/ui/src/hooks/use-mobile.ts (1)
  • useIsMobile (7-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (1)
apps/web/src/components/agent/edit.tsx (1)

1-583: Previous critical issues have been successfully addressed.

All previously flagged critical issues regarding nested providers, thread ID management, and missing imports have been properly resolved:

  • ✓ No nested DecopilotLayout causing duplicated panels
  • ✓ Thread IDs correctly wired: agent mode uses threadId prop (line 354), decopilot mode uses effectiveDecopilotThreadId (line 372)
  • ✓ No nested DecopilotProvider causing context reset
  • useRef properly imported (line 37)
  • ✓ Both providers maintain separate state while sharing the outer layout

The current architecture with dual providers (lines 345-395) correctly isolates agent and decopilot chat states while preserving state when switching modes.

@abdulhdr1
Copy link
Copy Markdown
Contributor Author

LGTM!

How was this Agent|Chat built?

it's just shadcn's button group with some radio-button-like selection/highlight for the selected chat

image I'd love the PR even more if this was just "a view that is pinned at the top" from this current app (in this case, the Agent Editor app).

It's impossible to overlook that a button with Agent | Chat looks confusing.

It's indeed confusing, I'm more aligned now on what a better solution would be, I'll make some prototypes and circle back on it.
I merged the PR because there are other changes, and IMO this way, although not best, is still better than the previous double chat problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants