-
Notifications
You must be signed in to change notification settings - Fork 67
feat(chat): add web search mode toggle for Chat Shell #790
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Implement frontend control for web search behavior in Chat mode with three selectable modes: - Auto: AI decides whether to search (default behavior) - On: Force search with specified engine - Off: Disable search completely Changes include: - Extended SearchEngineSelector component with three-state mode - Added web search state management with localStorage persistence - Updated WebSocket payload to support force/disable search flags - Added force web search prompt injection in backend - Implemented search tool registration logic based on mode - Added i18n translations for search modes (zh-CN and en) The feature is only visible for Chat Shell bots when WEB_SEARCH_ENABLED is true in backend configuration.
📝 WalkthroughWalkthroughThis PR implements granular web search configuration controls across the full stack. It adds two new boolean flags ( Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
backend/app/services/chat/config/stream_config.py (1)
58-59: Add validation for mutually exclusive flags.Similar to the frontend,
force_web_searchanddisable_web_searchare mutually exclusive but not enforced. When both areTrue, the behavior is ambiguous. Consider adding a validation method to the dataclass:🔎 Proposed validation
@dataclass class WebSocketStreamConfig: """Configuration for WebSocket streaming. Attributes: task_id: Task ID for the chat session subtask_id: Assistant subtask ID task_room: WebSocket room name for broadcasting user_id: User ID for permission checks and history loading user_name: User name for group chat message prefix is_group_chat: Whether this is a group chat (affects message prefix and history truncation) message_id: Assistant's message_id for frontend ordering user_message_id: User's message_id for history exclusion (prevents duplicate messages) enable_web_search: Enable web search tool search_engine: Specific search engine to use bot_name: Bot name for MCP server loading bot_namespace: Bot namespace shell_type: Shell type (Chat, ClaudeCode, Agno) for frontend display extra_tools: Additional tools (e.g., KnowledgeBaseTool) """ # Task identification task_id: int subtask_id: int task_room: str # User context user_id: int user_name: str is_group_chat: bool = False # Message ordering context message_id: int | None = None # Assistant's message_id for ordering in frontend user_message_id: int | None = None # User's message_id for history exclusion # Feature flags enable_tools: bool = True # Enable tools (MCP, web search, skills, etc.) enable_web_search: bool = False search_engine: str | None = None force_web_search: bool = False # Force AI to perform web search at least once disable_web_search: bool = False # Completely disable web search tool # Prompt enhancement options enable_clarification: bool = False enable_deep_thinking: bool = True skills: list[dict] = field( default_factory=list ) # Skill metadata for prompt injection # Bot configuration bot_name: str = "" bot_namespace: str = "default" shell_type: str = "Chat" # Shell type for frontend display extra_tools: list[BaseTool] = field(default_factory=list) + def __post_init__(self): + """Validate that mutually exclusive flags are not both set.""" + if self.force_web_search and self.disable_web_search: + raise ValueError( + "force_web_search and disable_web_search cannot both be True" + ) + def get_username_for_message(self) -> str | None: """Get username for message prefix in group chat mode.""" return self.user_name if self.is_group_chat else Nonebackend/app/api/ws/events.py (1)
106-113: Consider adding validation for mutually exclusive flags.The
force_web_searchanddisable_web_searchflags are semantically mutually exclusive—enabling both simultaneously would be contradictory. While the frontend appears to handle this correctly, consider adding a Pydanticmodel_validatorto enforce this constraint at the API boundary.🔎 Optional: Add model validator
+from pydantic import BaseModel, Field, model_validator + class ChatSendPayload(BaseModel): """Payload for chat:send event.""" # ... existing fields ... force_web_search: bool = Field( False, description="Force AI to perform web search at least once" ) disable_web_search: bool = Field( False, description="Completely disable web search tool" ) + + @model_validator(mode='after') + def validate_web_search_flags(self) -> 'ChatSendPayload': + if self.force_web_search and self.disable_web_search: + raise ValueError("Cannot both force and disable web search") + return self
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
backend/app/api/ws/events.pybackend/app/chat_shell/agent.pybackend/app/chat_shell/prompts/builder.pybackend/app/services/chat/config/stream_config.pybackend/app/services/chat/streaming/ws_handler.pybackend/app/services/chat/trigger/core.pyfrontend/src/features/tasks/components/chat/ChatArea.tsxfrontend/src/features/tasks/components/chat/useChatAreaState.tsfrontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxfrontend/src/features/tasks/components/input/ChatInputCard.tsxfrontend/src/features/tasks/components/input/ChatInputControls.tsxfrontend/src/features/tasks/components/selector/SearchEngineSelector.tsxfrontend/src/features/tasks/contexts/chatStreamContext.tsxfrontend/src/i18n/locales/en/chat.jsonfrontend/src/i18n/locales/zh-CN/chat.jsonfrontend/src/types/socket.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{py,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{py,ts,tsx,js,jsx}: All code comments MUST be written in English
File size limit: If a file exceeds 1000 lines, split it into multiple sub-modules
Max 50 lines per function (preferred)
Extract common logic into shared utilities to avoid duplication
Files:
frontend/src/features/tasks/contexts/chatStreamContext.tsxfrontend/src/types/socket.tsfrontend/src/features/tasks/components/chat/ChatArea.tsxfrontend/src/features/tasks/components/input/ChatInputCard.tsxbackend/app/services/chat/config/stream_config.pybackend/app/services/chat/streaming/ws_handler.pyfrontend/src/features/tasks/components/chat/useChatAreaState.tsbackend/app/api/ws/events.pyfrontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxfrontend/src/features/tasks/components/input/ChatInputControls.tsxfrontend/src/features/tasks/components/selector/SearchEngineSelector.tsxbackend/app/chat_shell/prompts/builder.pybackend/app/services/chat/trigger/core.pybackend/app/chat_shell/agent.py
frontend/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
frontend/src/**/*.{ts,tsx,js,jsx}: TypeScript/React frontend code must use TypeScript strict mode, functional components, Prettier formatting, ESLint, single quotes, and no semicolons
Useconstoverlet, nevervarin TypeScript/React code
Files:
frontend/src/features/tasks/contexts/chatStreamContext.tsxfrontend/src/types/socket.tsfrontend/src/features/tasks/components/chat/ChatArea.tsxfrontend/src/features/tasks/components/input/ChatInputCard.tsxfrontend/src/features/tasks/components/chat/useChatAreaState.tsfrontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxfrontend/src/features/tasks/components/input/ChatInputControls.tsxfrontend/src/features/tasks/components/selector/SearchEngineSelector.tsx
frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
frontend/src/**/*.{ts,tsx}: Extract reusable logic when implementing similar UI patterns multiple times; avoid duplication through composition over copy-paste
UsemessagesfromuseUnifiedMessagesas the single source of truth for displayed messages; never useselectedTaskDetail.subtasksfor display/export
Always import i18n translations from@/hooks/useTranslation, not fromreact-i18next
Use single namespace matching your feature when callinguseTranslation()(e.g.,useTranslation('groups')for groups feature); never use array withcommonfirst
Within current i18n namespace uset('key.subkey')format; from other namespace uset('namespace:key.subkey')format
Use responsive breakpoints withuseIsMobile()for max-width 767px anduseIsDesktop()for min-width 1024px
Files:
frontend/src/features/tasks/contexts/chatStreamContext.tsxfrontend/src/types/socket.tsfrontend/src/features/tasks/components/chat/ChatArea.tsxfrontend/src/features/tasks/components/input/ChatInputCard.tsxfrontend/src/features/tasks/components/chat/useChatAreaState.tsfrontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxfrontend/src/features/tasks/components/input/ChatInputControls.tsxfrontend/src/features/tasks/components/selector/SearchEngineSelector.tsx
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Frontend: Only use
NEXT_PUBLIC_*environment variables for client-safe values
Files:
frontend/src/features/tasks/contexts/chatStreamContext.tsxfrontend/src/types/socket.tsfrontend/src/features/tasks/components/chat/ChatArea.tsxfrontend/src/features/tasks/components/input/ChatInputCard.tsxfrontend/src/features/tasks/components/chat/useChatAreaState.tsfrontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxfrontend/src/features/tasks/components/input/ChatInputControls.tsxfrontend/src/features/tasks/components/selector/SearchEngineSelector.tsx
frontend/src/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
frontend/src/**/*.{tsx,jsx}: Tailwind CSS color system usage: usebg-basefor page background,text-text-primaryfor primary text,bg-surfacefor cards/panels
Tailwind CSS typography: Usetext-xl font-semiboldfor H1,text-lg font-semiboldfor H2,text-smfor body text,text-xs text-text-mutedfor small text
Files:
frontend/src/features/tasks/contexts/chatStreamContext.tsxfrontend/src/features/tasks/components/chat/ChatArea.tsxfrontend/src/features/tasks/components/input/ChatInputCard.tsxfrontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxfrontend/src/features/tasks/components/input/ChatInputControls.tsxfrontend/src/features/tasks/components/selector/SearchEngineSelector.tsx
frontend/src/types/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript types should be organized in
src/types/
Files:
frontend/src/types/socket.ts
frontend/src/i18n/locales/**/*.{json,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Add new i18n translation keys to the appropriate namespace file in
src/i18n/locales/{lang}/
Files:
frontend/src/i18n/locales/en/chat.jsonfrontend/src/i18n/locales/zh-CN/chat.json
backend/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
backend/**/*.py: Python backend code must follow PEP 8 standard with Black formatter (line length: 88) and isort
For Task/Workspace CRDs use TaskResource model fromapp.models.task; for other CRDs (Ghost, Model, Shell, Bot, Team, Skill) use Kind model fromapp.models.kind
Backend encrypts Git tokens and API keys using AES-256-CBC
Web search feature: Configure withWEB_SEARCH_ENABLED(default false),WEB_SEARCH_ENGINESJSON config, andWEB_SEARCH_DEFAULT_MAX_RESULTS(default 100)
MCP server configuration: UseCHAT_MCP_ENABLEDto enable/disable MCP tools in Chat Shell mode, configure withCHAT_MCP_SERVERSJSON supporting${{path}}variable substitution (user.name, user.id)
Files:
backend/app/services/chat/config/stream_config.pybackend/app/services/chat/streaming/ws_handler.pybackend/app/api/ws/events.pybackend/app/chat_shell/prompts/builder.pybackend/app/services/chat/trigger/core.pybackend/app/chat_shell/agent.py
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code requires type hints
Python code must include descriptive names and docstrings for public functions/classes
Extract magic numbers to constants in Python code
Files:
backend/app/services/chat/config/stream_config.pybackend/app/services/chat/streaming/ws_handler.pybackend/app/api/ws/events.pybackend/app/chat_shell/prompts/builder.pybackend/app/services/chat/trigger/core.pybackend/app/chat_shell/agent.py
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-29T10:42:55.732Z
Learning: Applies to backend/**/*.py : Web search feature: Configure with `WEB_SEARCH_ENABLED` (default false), `WEB_SEARCH_ENGINES` JSON config, and `WEB_SEARCH_DEFAULT_MAX_RESULTS` (default 100)
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to backend/app/services/search/**/*.py : Backend MUST support web search feature configuration via `WEB_SEARCH_*` environment variables with adapter configuration
📚 Learning: 2025-12-29T10:42:55.732Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-29T10:42:55.732Z
Learning: Applies to frontend/src/**/*.{ts,tsx} : Use `messages` from `useUnifiedMessages` as the single source of truth for displayed messages; never use `selectedTaskDetail.subtasks` for display/export
Applied to files:
frontend/src/features/tasks/contexts/chatStreamContext.tsxfrontend/src/features/tasks/components/chat/ChatArea.tsxfrontend/src/features/tasks/components/chat/useChatAreaState.tsfrontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx
📚 Learning: 2025-12-29T10:42:55.732Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-29T10:42:55.732Z
Learning: Applies to backend/**/*.py : Web search feature: Configure with `WEB_SEARCH_ENABLED` (default false), `WEB_SEARCH_ENGINES` JSON config, and `WEB_SEARCH_DEFAULT_MAX_RESULTS` (default 100)
Applied to files:
frontend/src/types/socket.tsfrontend/src/i18n/locales/en/chat.jsonbackend/app/services/chat/config/stream_config.pybackend/app/services/chat/streaming/ws_handler.pybackend/app/api/ws/events.pyfrontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to frontend/src/i18n/zh-CN.json : Frontend i18n Chinese values (zh-CN) MUST use UI terms: `'智能体列表'`, `'机器人配置'`
Applied to files:
frontend/src/i18n/locales/en/chat.jsonfrontend/src/i18n/locales/zh-CN/chat.json
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to frontend/src/**/*.tsx : Frontend component files named with CRD terms: team-list.tsx, bot-form.tsx, model-selector.tsx
Applied to files:
frontend/src/features/tasks/components/chat/ChatArea.tsxfrontend/src/features/tasks/components/input/ChatInputCard.tsxfrontend/src/features/tasks/components/input/ChatInputControls.tsx
📚 Learning: 2025-12-29T10:42:55.732Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-29T10:42:55.732Z
Learning: Applies to frontend/src/**/*.{ts,tsx} : Always import i18n translations from `@/hooks/useTranslation`, not from `react-i18next`
Applied to files:
frontend/src/features/tasks/components/chat/ChatArea.tsx
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to backend/app/services/search/**/*.py : Backend MUST support web search feature configuration via `WEB_SEARCH_*` environment variables with adapter configuration
Applied to files:
backend/app/services/chat/config/stream_config.pybackend/app/services/chat/streaming/ws_handler.py
🧬 Code graph analysis (5)
frontend/src/features/tasks/contexts/chatStreamContext.tsx (1)
frontend/src/apis/client.ts (1)
request(57-121)
frontend/src/features/tasks/components/chat/ChatArea.tsx (1)
frontend/src/apis/chat.ts (2)
SearchEngine(295-298)getSearchEngines(313-339)
frontend/src/features/tasks/components/chat/useChatAreaState.ts (1)
frontend/src/features/tasks/components/selector/SearchEngineSelector.tsx (1)
WebSearchMode(29-29)
frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx (1)
frontend/src/features/tasks/components/selector/SearchEngineSelector.tsx (1)
WebSearchMode(29-29)
frontend/src/features/tasks/components/selector/SearchEngineSelector.tsx (5)
frontend/src/hooks/useTranslation.ts (1)
useTranslation(8-30)frontend/src/components/ui/tooltip.tsx (4)
TooltipProvider(34-34)Tooltip(34-34)TooltipTrigger(34-34)TooltipContent(34-34)frontend/src/components/ui/button.tsx (1)
Button(56-56)frontend/src/lib/utils.ts (1)
cn(8-10)frontend/src/components/ui/dropdown.tsx (6)
DropdownMenu(178-178)DropdownMenuTrigger(179-179)DropdownMenuContent(180-180)DropdownMenuLabel(184-184)DropdownMenuItem(181-181)DropdownMenuSeparator(185-185)
⏰ 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). (7)
- GitHub Check: E2E Tests (Shard 1/3)
- GitHub Check: Test wegent CLI Integration
- GitHub Check: E2E Tests (Shard 3/3)
- GitHub Check: E2E Tests (Shard 2/3)
- GitHub Check: Test Backend (3.11)
- GitHub Check: Test Backend (3.10)
- GitHub Check: Test Frontend
🔇 Additional comments (24)
frontend/src/i18n/locales/zh-CN/chat.json (1)
235-242: LGTM! Clear and consistent i18n additions.The web search mode translations are well-structured with clear descriptions for each mode. The naming pattern is consistent, and the Chinese translations accurately convey the intended meaning.
backend/app/chat_shell/agent.py (2)
317-317: Correct propagation of force_web_search to prompt builder.The flag is correctly passed to
build_system_promptfor prompt enhancement.
53-53: Prompt builder correctly handlesforce_web_searchflag.The flag is properly passed from
AgentConfigtobuild_system_prompt(), which uses it to conditionally appendFORCE_WEB_SEARCH_PROMPTvia theappend_force_web_search_prompt()helper. The injected prompt text contains meaningful instructions ("MANDATORY Web Search Requirement") that direct the AI to use the web_search tool at least once before responding. Implementation is complete and correct.backend/app/services/chat/streaming/ws_handler.py (2)
144-156: LGTM! Correct three-state web search logic.The implementation correctly handles the three web search modes:
- Off (
disable_web_search=True): Web search tool is not registered (line 145)- Auto (
disable_web_search=False,force_web_search=False): Web search tool is available for AI to use- On (
disable_web_search=False,force_web_search=True): Web search tool is available AND prompt forces usageThe condition
settings.WEB_SEARCH_ENABLED and not config.disable_web_searchcorrectly implements the tool registration logic for modes 2 and 3.
190-190: Correct propagation of force_web_search to AgentConfig.The flag is properly forwarded from the WebSocket stream config to the agent configuration, enabling prompt-level control of web search behavior.
frontend/src/i18n/locales/en/chat.json (1)
235-242: LGTM! Clear and user-friendly English translations.The web search mode translations are well-written with concise descriptions that clearly explain each mode's behavior. The translations align well with the Chinese versions and maintain consistency with the existing i18n patterns.
frontend/src/features/tasks/contexts/chatStreamContext.tsx (2)
185-188: Correct interface extension for web search control.The
ChatMessageRequestinterface is properly extended with the two new optional boolean fields, maintaining consistency with the existing optional parameters pattern.Note: The mutual exclusivity concern for these flags was already raised in the review of
frontend/src/types/socket.ts. Consider addressing it at the interface level rather than in every usage site.
1161-1162: Correct payload construction with web search flags.The implementation correctly extracts the web search control flags from the request and includes them in the WebSocket payload, following the established pattern for other optional fields.
backend/app/services/chat/trigger/core.py (1)
441-442: Correct flag propagation from payload to config.The implementation correctly extracts and forwards the web search control flags from the validated payload to the WebSocket stream configuration. The
ChatSendPayloadPydantic model validates bothforce_web_searchanddisable_web_searchfields before the handler executes (via the@auto_task_contextdecorator), ensuring type safety and proper defaults. The flags are then correctly propagated toWebSocketStreamConfigwhich declares both fields.frontend/src/features/tasks/components/input/ChatInputCard.tsx (1)
109-114: LGTM!Web search props are correctly threaded through to
ChatInputControls. The prop forwarding pattern is consistent with the existing code structure.Also applies to: 223-228
frontend/src/features/tasks/components/chat/ChatArea.tsx (2)
70-88: LGTM!The search engines configuration fetch is well-implemented with proper error handling that gracefully falls back to safe defaults. The separation between backend configuration (
webSearchEnabled,searchEngines) and user preferences (webSearchMode,selectedSearchEnginefromchatState) is clean.
361-367: LGTM!Web search props are correctly assembled and passed to
ChatInputCard. The comment clarifies the prop grouping.frontend/src/features/tasks/components/chat/useChatAreaState.ts (2)
224-235: LGTM!The localStorage persistence implementation is well-designed with proper SSR safety checks and validation of the saved mode value against the allowed types.
237-251: LGTM!The setter callbacks correctly persist to localStorage with SSR guards. Using
useCallbackensures stable function references.frontend/src/features/tasks/components/input/ChatInputControls.tsx (1)
264-274: LGTM!The
SearchEngineSelectorintegration follows the established pattern for chat shell controls, with appropriate conditional rendering and disabled state handling.backend/app/chat_shell/prompts/builder.py (2)
251-280: LGTM!The
FORCE_WEB_SEARCH_PROMPTandappend_force_web_search_promptfunction follow the established patterns for other prompt modifiers in this module. The prompt text is clear and imperative about the mandatory search requirement.
303-344: LGTM!The
build_system_promptfunction is cleanly extended with theforce_web_searchparameter, maintaining consistency with other optional prompt enhancements.frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx (2)
536-567: LGTM!Dependencies are correctly updated to include
webSearchModeandselectedSearchEngine, ensuring the callback refreshes when web search preferences change.
470-477: Remove this concern—the flags serve different purposes.
enable_web_searchandforce_web_searchare not redundant. Backend analysis shows they control different aspects:enable_web_searchdetermines whether the WebSearchTool is registered at all (line 106 ofbackend/app/chat_shell/agent.py), whileforce_web_searchinstructs the AI to perform a search by injecting special instructions into the system prompt (lines 267–280 ofbackend/app/chat_shell/prompts/builder.py). Both being true whenwebSearchMode === 'on'is correct—the tool must be available and the AI must be explicitly told to use it.frontend/src/features/tasks/components/selector/SearchEngineSelector.tsx (5)
23-29: LGTM!The
WebSearchModetype is well-documented and exported for use across the codebase. The three-state model (auto/on/off) provides clear semantic meaning.
53-57: Verify: potential re-render loop in useEffect.This
useEffectcallsonSelectEnginewhenselectedEngineis null and engines exist. IfonSelectEngineis not memoized in the parent component, this could cause re-renders. The parent (useChatAreaState) usesuseCallbackforsetSelectedSearchEngine, so this should be safe, but worth noting.
63-88: LGTM!The
getModeInfohelper cleanly encapsulates mode-specific UI configuration. The icon, label, description, and color mappings are consistent with the design intent.
96-102: LGTM!Auto-setting mode to 'on' when an engine is selected is good UX—it avoids the confusing state where an engine is selected but mode is still 'auto' or 'off'.
131-203: LGTM!The dropdown UI is well-structured with clear visual hierarchy. Mode selection is separated from engine selection, and the check marks provide clear feedback on current selections.
| force_web_search?: boolean; // Force AI to perform web search | ||
| disable_web_search?: boolean; // Completely disable web search tool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider documenting precedence or adding validation for mutually exclusive flags.
The force_web_search and disable_web_search flags are logically mutually exclusive (you cannot both force and disable web search). However, the type system allows both to be true simultaneously. Consider either:
- Adding JSDoc comments to document which flag takes precedence if both are set
- Adding runtime validation in the frontend before sending the payload
- Using a discriminated union type to enforce mutual exclusivity at compile time
For example, a more type-safe approach could use a single webSearchMode field:
web_search_mode?: 'auto' | 'force' | 'disable';🔎 Alternative type-safe approach
- force_web_search?: boolean; // Force AI to perform web search
- disable_web_search?: boolean; // Completely disable web search tool
+ /** Web search mode: 'auto' (default), 'force', or 'disable' */
+ web_search_mode?: 'auto' | 'force' | 'disable';This would require updating the backend to accept this field instead of two separate booleans.
Implement frontend control for web search behavior in Chat mode with three selectable modes:
Changes include:
The feature is only visible for Chat Shell bots when WEB_SEARCH_ENABLED is true in backend configuration.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.