Conversation
|
Caution Review failedThe pull request is closed. WalkthroughReplaces single Chat with UnifiedChat/ChatWithProvider and adds a PreviewContext for URL-synced chatMode and mobile preview toggles; extends ChatInput/ContextResources with a Changes
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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (6)
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. Comment |
Deploying chat with
|
| 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 |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (11)
apps/web/src/components/agent/edit.tsx (5)
132-148: Prevent header overlap on long agent namesAbsolute-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 DecopilotLayoutThis 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 threadkey={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-linksState 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
rightNodedoesn't need to be wrapped in adivsince it's already aReactNodeand 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
📒 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.jsonpackages/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 explicitlyPrefer 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.tsxapps/web/src/hooks/use-file-upload.tsapps/web/src/components/chat/chat-input.tsxapps/web/src/components/integrations/tabs/connection-tabs.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/integrations/tabs/connection-tabs.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/hooks/use-file-upload.tsapps/web/src/components/chat/chat-input.tsxapps/web/src/components/integrations/tabs/connection-tabs.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/integrations/tabs/connection-tabs.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/integrations/tabs/connection-tabs.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/project.tsxapps/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.tsapps/web/src/components/chat/chat-input.tsxapps/web/src/components/integrations/tabs/connection-tabs.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/project.tsxapps/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.tsapps/web/src/components/chat/chat-input.tsxapps/web/src/components/integrations/tabs/connection-tabs.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/project.tsxapps/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.tsapps/web/src/components/chat/chat-input.tsxapps/web/src/components/integrations/tabs/connection-tabs.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/project.tsxapps/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 solidMerging 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--sidebarand 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
Onlypackages/uideclares^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
rightNodeprop enables the component to accept custom UI elements (e.g., preview toggles), improving composability and reusability.Also applies to: 54-54
| import { | ||
| type FormEvent, | ||
| type KeyboardEvent, | ||
| type ReactNode, | ||
| useEffect, | ||
| } from "react"; |
There was a problem hiding this comment.
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.
| 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".
| export function ChatInput({ | ||
| disabled, | ||
| rightNode, | ||
| }: { disabled?: boolean; rightNode?: ReactNode } = {}) { |
There was a problem hiding this comment.
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.
| 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.
There was a problem hiding this comment.
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/dragleavedragleave 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 typeYou 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-fitThese 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 tomargin: 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 handlerThe 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 onceTo 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 slashisAgentDetailPage 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 booleanKeep 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 hookUse
useIsMobile()from@deco/ui/hooks/use-mobile.tsfor 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: RenderrightNodeas a footer fallback whenshowContextResourcesis false
rightNodeis only passed into<ContextResources>(gated byshowContextResources), 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 mismatchThe Decopilot AgentProvider is keyed by
threadState.threadIdbut receivesthreadId={decopilotThreadId}(a stable UUID). This forces remounts without actually switching thread IDs. Either bind the prop to the samethreadState.threadIdyou 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.threadIdis 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 togglesYou read
chatfromlocation.searchand exposesetChatMode, 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
📒 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.jsonpackages/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 explicitlyPrefer 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.tsxapps/web/src/components/layout/decopilot-layout.tsxpackages/ui/src/components/button-group.tsxapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/project.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsxapps/web/src/components/layout/decopilot-layout.tsxpackages/ui/src/components/button-group.tsxapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/project.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/project.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/project.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsxapps/web/src/components/layout/decopilot-layout.tsxpackages/ui/src/components/button-group.tsxapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/project.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsxapps/web/src/components/layout/decopilot-layout.tsxpackages/ui/src/components/button-group.tsxapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/layout/decopilot-layout.tsxpackages/ui/src/components/button-group.tsxapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/project.tsxapps/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 goodNon-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 goodUsing
type ReactNodeis correct and tree-shake friendly.
20-26: Propagate right-side slot viarightNodeAPI shape is clear and backward‑compatible.
apps/web/src/components/agent/edit.tsx (9)
60-79: PreviewContext setup is cleanType-safe context + guard hook; fits the usage pattern in this file.
118-148: Header layout changes prevent shiftsAbsolute positioning for actions and reserved padding (
pr-24) is a good call to avoid layout jitter.
155-156: Good use ofrightNodeto surface mobile toggle in chatPassing
rightNode={<PreviewToggleButton />}aligns with the new slot and keeps concerns separated.
218-236: Mobile-only PreviewToggleButtonSimple and clear; returns null on desktop.
270-275: Floating mobile toggleFloating action placement for mobile is sensible and non-intrusive.
472-489: Provider composition is sensiblePreviewContext wraps AgentProvider; ResponsiveLayout uses both correctly.
294-336: Guard decopilot-only context mergesMerging rules and tools only in decopilot mode is correct. Minor: if both
appAdditionalToolsandcontextToolsshare keys, later values override earlier; confirm this is intended.
309-317: agentId fallback safetyReturning
nullwhen!chatAgentIdis 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.
There was a problem hiding this comment.
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 aroundrightNodeis 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 instancesAs 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 cnSelf-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 ReactForwarding 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 managementEnables 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 ButtonGroupTextAllows 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 SeparatorKeeps 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 hookInline regex
/agent/[^/]+/[^/]+$/is duplicated in:
apps/web/src/components/layout/project.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/settings/integrations.tsxapps/web/src/components/agents/hooks.tsapps/web/src/components/settings/usage/agents-table.tsxCreate a
useIsAgentDetailRoute(or similar) hook that uses React Router’suseMatch('/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 useMatchMultiple files construct or detect
/agent/:id/:threadId(e.g., decopilot-layout, integrations.tsx, agents-table.tsx, agents/hooks.ts). Centralize this pattern in anisAgentDetailPath(pathname)util or replace the regex withuseMatch("/agent/:agentId/:threadId")to prevent duplication and drift.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 explicitlyPrefer 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.tsapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxpackages/ui/src/components/button-group.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsapps/web/src/components/chat/context-resources.tsxapps/web/src/components/chat/chat-input.tsxpackages/ui/src/components/button-group.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsxapps/web/src/components/chat/chat-input.tsxpackages/ui/src/components/button-group.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsxapps/web/src/components/chat/chat-input.tsxpackages/ui/src/components/button-group.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsxapps/web/src/components/chat/chat-input.tsxpackages/ui/src/components/button-group.tsxapps/web/src/components/layout/decopilot-layout.tsxapps/web/src/components/agent/edit.tsxapps/web/src/components/layout/topbar.tsxapps/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.tsxpackages/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
rightNodeprop 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 ofjustify-between items-endin chat context; test:
- Multiple integrations/files/rules wrapping to multiple lines
- Mobile viewport behavior with
items-endalignment- Alignment of the preview toggle (
rightNode) when content wrapsapps/web/src/components/chat/chat-input.tsx (1)
4-9: LGTM!The
rightNodeprop is properly typed, threaded through toContextResources, 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 variantsClasses 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.
| globalThis.addEventListener("drag", handleDrag); | ||
| globalThis.addEventListener("dragover", handleDragOver); | ||
| globalThis.addEventListener("dragend", handleDragEnd); | ||
| globalThis.addEventListener("dragleave", handleDragEnd); |
There was a problem hiding this comment.
🧩 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.tsLength 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.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/web/src/components/agent/edit.tsx (1)
432-442: Consider if the useEffect is necessary.The
useEffecton Lines 440-442 syncschatModestate with the URL parameter. However, sinceurlChatModeis computed fromlocation.searchwhich changes when the URL changes, you could directly useurlChatModewithout 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
setChatModeto 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
📒 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 explicitlyPrefer 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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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
AgentAvatarprovides 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 definitionagent/:id/:threadIdinapps/web/src/main.tsx:430, so no change is needed.Likely an incorrect or invalid review comment.
160-216: AgentChatModeSwitchagentIdguard sufficient; confirm error boundary.
AgentChatModeSwitchonly renders on agent detail pages (isAgentDetailPage), soagentIdfromuseParams()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
chatModeproperly 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
chatModeandeditingAgent, 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:
DecopilotLayout→PreviewContext→AgentProvider→ResponsiveLayout. Document metadata is properly configured with agent information.
280-390: AgentProvider cleans up subscriptions on unmount
TheuseEffectforonRulesUpdatedreturns 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
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (4)
apps/web/src/components/layout/project.tsx (1)
169-173: Good guard before useAgentData avoids invalid suspense fetchesEarly-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 correctTopbarControls 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 functionalityTitle and icon now reflect “Add integrations.” Looks good.
apps/web/src/components/agent/edit.tsx (1)
297-387: Decopilot thread id is now correctly appliedeffectiveDecopilotThreadId 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 modeAlign the button text with the decopilot agent.
Apply:
- Chat + Decopilot
245-261: Route check with regex is brittle; use useMatch for route-shape safetyuseMatch 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 awaitonRemove 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 imagesUse 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 FormProviderFormProvider 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
📒 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 explicitlyPrefer 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.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/project.tsxapps/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.tsxapps/web/src/components/layout/topbar.tsxapps/web/src/components/layout/project.tsxapps/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.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 explicitlyPrefer 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
|
I expected the name would be updated Screen.Recording.2025-10-14.at.08.57.44.mov |
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 explicitlyPrefer 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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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-24padding (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
showPreviewis straightforward.
469-486: Mobile detection and chat mode state management is well-structured.The URL-synced
chatModestate (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.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 explicitlyPrefer 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)
…er and ResponsiveLayout components for improved state management
There was a problem hiding this comment.
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, andallRulescomputations (lines 320-341) could be combined into a singleuseMemohook 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. ThechatAgentIdis derived from eitherWELL_KNOWN_AGENTS.decopilotAgent.id(always defined) oragentId. The parentPagecomponent (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 existingsetChatModein auseCallbackthat also updates thechatsearch param via React Router’snavigate(oruseSearchParams), then pass this wrapped setter intoPreviewContext.Providerso state and URL stay in sync.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 explicitlyPrefer 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
DecopilotLayoutcausing duplicated panels- ✓ Thread IDs correctly wired: agent mode uses
threadIdprop (line 354), decopilot mode useseffectiveDecopilotThreadId(line 372)- ✓ No nested
DecopilotProvidercausing context reset- ✓
useRefproperly 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.
it's just shadcn's button group with some radio-button-like selection/highlight for the selected chat
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. |


What is this contribution about?
Fixes:
Screenshots/Demonstration
Screen.Recording.2025-10-13.at.18.22.50.mov
Review Checklist
Summary by CodeRabbit
New Features
UX Improvements
Chores