fix(frontend): fix history chat cannot continue issue#1022
fix(frontend): fix history chat cannot continue issue#1022parabala wants to merge 1 commit intowecode-ai:mainfrom
Conversation
📝 WalkthroughWalkthroughRefactors WebSocket room join/rejoin logic and chat-team validation: taskContext splits join logic into selection-driven and reconnection-driven effects; ChatArea falls back to Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsTimed out fetching pipeline failures after 30000ms 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.
🧹 Nitpick comments (1)
frontend/src/features/tasks/contexts/taskContext.tsx (1)
718-760: Keep only one reconnect join path and fix the stale note.Line 733 and Line 751 can both call
joinTask(selectedTask.id)on reconnect because the selected-task effect already depends onisConnected. Deduplication makes this mostly safe, but Lines 756-760 now directly contradict the new separate reconnect effect.Consider either:
- keep the separate reconnect effect and remove
isConnectedfrom the selected-task effect dependencies, or- rely on the selected-task effect and remove the separate reconnect effect.
♻️ Proposed cleanup if keeping the separate reconnect effect
- }, [selectedTask, leaveTask, joinTask, isConnected]) + }, [selectedTask, leaveTask, joinTask]) // Separate effect to handle WebSocket reconnection // When WebSocket reconnects, rejoin the current task room if there is one useEffect(() => { // Only proceed if WebSocket is connected and there is a selected task if (isConnected && selectedTask) { // Rejoin the task room to ensure we receive real-time updates // joinTask has built-in deduplication, so it's safe to call again joinTask(selectedTask.id) } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isConnected]) - - // NOTE: Removed separate isConnected useEffect to prevent duplicate joinTask calls. - // The selectedTask useEffect above now handles both cases: - // 1. When selectedTask changes (and isConnected is true) - // 2. When isConnected changes (and selectedTask is set) - // This is because we added isConnected to the dependency array. + }, [isConnected, selectedTask, joinTask])🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/features/tasks/contexts/taskContext.tsx` around lines 718 - 760, The code currently has two paths that can call joinTask(selectedTask.id) on reconnect: the selected-task useEffect (which includes isConnected in its dependency array) and the separate reconnection useEffect, causing duplicate/contradictory logic; pick one approach and consolidate: either (A) keep the separate reconnection effect and remove isConnected from the dependency array of the selected-task useEffect (so selected-task effect only reacts to selectedTask changes and uses previousTaskIdRef, leaveTask, joinTask, refreshSelectedTaskDetail, setSelectedTaskDetail), or (B) remove the separate reconnection useEffect entirely and keep isConnected in the selected-task useEffect dependencies (so selected-task effect handles both selectedTask and reconnect scenarios); update or remove the explanatory NOTE accordingly and ensure only one place calls joinTask on reconnect to avoid duplicated logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@frontend/src/features/tasks/contexts/taskContext.tsx`:
- Around line 718-760: The code currently has two paths that can call
joinTask(selectedTask.id) on reconnect: the selected-task useEffect (which
includes isConnected in its dependency array) and the separate reconnection
useEffect, causing duplicate/contradictory logic; pick one approach and
consolidate: either (A) keep the separate reconnection effect and remove
isConnected from the dependency array of the selected-task useEffect (so
selected-task effect only reacts to selectedTask changes and uses
previousTaskIdRef, leaveTask, joinTask, refreshSelectedTaskDetail,
setSelectedTaskDetail), or (B) remove the separate reconnection useEffect
entirely and keep isConnected in the selected-task useEffect dependencies (so
selected-task effect handles both selectedTask and reconnect scenarios); update
or remove the explanatory NOTE accordingly and ensure only one place calls
joinTask on reconnect to avoid duplicated logic.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 426c0ac9-1402-4bf4-9853-c224b995a9c5
📒 Files selected for processing (1)
frontend/src/features/tasks/contexts/taskContext.tsx
a465998 to
87e86ee
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
frontend/src/features/tasks/contexts/taskContext.tsx (1)
744-755: Avoid suppressing hook dependencies here.This effect reads
selectedTaskandjoinTaskbut only depends onisConnected. A rising-edge guard keeps the “only on reconnect” behavior while satisfying hook dependency rules.♻️ Proposed refactor
+ const wasConnectedRef = useRef(isConnected) + // Effect 2: Handle WebSocket reconnection // When WebSocket reconnects (isConnected changes from false to true), // rejoin the current task room to resume real-time updates useEffect(() => { + const wasConnected = wasConnectedRef.current + wasConnectedRef.current = isConnected + // Only proceed if WebSocket is connected and there is a selected task - if (isConnected && selectedTask) { + if (!wasConnected && isConnected && selectedTask) { // Rejoin the task room to ensure we receive real-time updates // joinTask has built-in deduplication (joinedTasksRef), so it's safe to call again joinTask(selectedTask.id) } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isConnected]) + }, [isConnected, selectedTask, joinTask])🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/features/tasks/contexts/taskContext.tsx` around lines 744 - 755, The effect currently uses selectedTask and joinTask but only lists isConnected in its dependency array and disables the lint rule; fix this by adding selectedTask and joinTask to the dependencies and implement a rising-edge guard (track previous isConnected with a ref like prevIsConnectedRef) so the body runs only when prevIsConnectedRef.current is false and isConnected is true; ensure you update prevIsConnectedRef after each render and call joinTask(selectedTask.id) only when selectedTask exists (the effect still preserves the “only on reconnect” behavior and avoids lint suppression).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@frontend/src/features/tasks/contexts/taskContext.tsx`:
- Around line 744-755: The effect currently uses selectedTask and joinTask but
only lists isConnected in its dependency array and disables the lint rule; fix
this by adding selectedTask and joinTask to the dependencies and implement a
rising-edge guard (track previous isConnected with a ref like
prevIsConnectedRef) so the body runs only when prevIsConnectedRef.current is
false and isConnected is true; ensure you update prevIsConnectedRef after each
render and call joinTask(selectedTask.id) only when selectedTask exists (the
effect still preserves the “only on reconnect” behavior and avoids lint
suppression).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 559bdeff-ae4a-41bb-8bf7-991aa4b69f9f
📒 Files selected for processing (1)
frontend/src/features/tasks/contexts/taskContext.tsx
When users click a history task to continue chatting, if WebSocket is not connected at that moment, the task room will not be joined. This causes the chat to not work properly because messages are not synced via WebSocket. Root cause: The original useEffect only handles joinTask when selectedTask changes. If WebSocket is disconnected when selectedTask is set, joinTask returns early with 'Not connected' error. When WebSocket reconnects later, there was no logic to rejoin the task room. Fix: Add a separate useEffect that monitors isConnected state. When WebSocket reconnects and there is a selected task, it automatically rejoins the task room. joinTask has built-in deduplication, so it's safe to call multiple times. Changes: - Add useEffect to handle WebSocket reconnection in taskContext.tsx - When isConnected becomes true and selectedTask exists, rejoin the task room - Update comments to clarify the logic
87e86ee to
ed2ee0c
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx (1)
170-1201: Split this hook before adding more send-path logic.This file is now 1203 lines, and the two send handlers are large enough that the new team validation was easy to apply inconsistently. Consider extracting payload construction, pending-context building, and validation/toast helpers.
As per coding guidelines, “File size limit: if a file exceeds 1000 lines, split it into multiple sub-modules” and “Maximum function length of 50 lines preferred for all functions”.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx` around lines 170 - 1201, The hook file has grown >1000 lines and the two large send handlers (handleSendMessage and handleSendMessageWithModel) contain duplicated logic and inconsistent team/validation/toast behavior; split this file by extracting: (1) payload construction logic used before contextSendMessage (move code that builds contextItems, messageWithQueueContent, queueAttachmentIds, inboxAttachmentContexts, pendingContexts and final request body into a helper like buildSendPayload), (2) pending-context/attachment mapping into a helper like buildPendingContexts, and (3) validation/toast checks (team selection, repo requirement, attachment upload state) into small functions like validateSendPreconditions and showSendErrorToast; import these helpers into useChatStreamHandlers and replace the inline blocks in handleSendMessage and handleSendMessageWithModel so both use the same shared helpers and maintain identical validation/messages and keep each function short.frontend/src/features/tasks/components/chat/ChatArea.tsx (1)
91-1309: Consider splittingChatAreaContentinto smaller modules.This component file is 1309 lines, making subtle state-sync changes harder to reason about. The team-sync effect, generation-mode state, message callbacks, and input props are good extraction candidates.
As per coding guidelines, “File size limit: if a file exceeds 1000 lines, split it into multiple sub-modules” and “Maximum function length of 50 lines preferred for all functions”.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/features/tasks/components/chat/ChatArea.tsx` around lines 91 - 1309, ChatAreaContent is too large (1309 lines); split responsibilities into focused sub-modules: extract the team-sync useEffect into a useTeamSync hook (referencing filteredTeams, selectedTaskDetail, taskIdFromUrl, handleTeamChange, hasInitializedTeamRef), move video/image generation state and related effects into useGenerateState (selectedResolution/Ratio/Duration, videoModelSelection, availableResolutions/ratios/durations, videoConfig, generateParams), move stream/message callbacks into useChatHandlers (streamHandlers creation and refs: handleSendMessageRef, handleRetryRef, handleSendMessageWithModelRef, handleReEdit, handleUseAsReference, handleQueueMessageLoaded), and extract inputCardProps construction into buildInputCardProps or ChatInputCardContainer (uses chatState, skillSelector, videoModelSelection/imageModelSelection, generateParams, streamHandlers); keep exported ChatAreaContent that composes these hooks/components and only contains top-level JSX and small glue logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/features/tasks/components/chat/ChatArea.tsx`:
- Line 119: The bug is that selectedTeam can remain unset when a user clicks
history because the component waits for selectedTaskDetail?.id; update the
selection logic in ChatArea to fall back to selectedTask.team_id whenever
selectedTask exists and its id equals the task id from the URL (route param) so
the team is synced immediately while details load. Locate the places using
selectedTaskDetail?.id (e.g., the current fallback computation and the blocks
around the earlier mention and lines ~316-327 and ~392-400) and change them to
check for selectedTaskDetail?.id OR (selectedTask && selectedTask.id ===
urlTaskId && selectedTask.team_id) and use selectedTask.team_id to set
selectedTeam/setSelectedTask accordingly.
In `@frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx`:
- Around line 455-463: The model-override/regeneration path is missing the same
team check and can send team_id: 0; update the send handlers to guard against
missing selectedTeam before sending by reusing the existing check logic (toast +
return) used earlier, specifically add the selectedTeam?.id guard in
handleSendMessageWithModel and in the other send/regenerate handler that
constructs messages for model-override (the same code path referenced around the
other send function), ensuring any send always early-returns with the
destructive toast when selectedTeam is absent instead of sending team_id: 0.
- Around line 459-460: The handleSendMessage callback uses the i18n translator
t() for error messages but t is not included in its dependency array, causing
stale translations and an exhaustive-deps lint violation; update the dependency
array of handleSendMessage to include t (the i18n translate function) so the
callback is recreated when the language changes, ensuring lines that call
t('chat:errors.team_not_selected') and
t('chat:errors.team_not_selected_description') use current translations.
---
Nitpick comments:
In `@frontend/src/features/tasks/components/chat/ChatArea.tsx`:
- Around line 91-1309: ChatAreaContent is too large (1309 lines); split
responsibilities into focused sub-modules: extract the team-sync useEffect into
a useTeamSync hook (referencing filteredTeams, selectedTaskDetail,
taskIdFromUrl, handleTeamChange, hasInitializedTeamRef), move video/image
generation state and related effects into useGenerateState
(selectedResolution/Ratio/Duration, videoModelSelection,
availableResolutions/ratios/durations, videoConfig, generateParams), move
stream/message callbacks into useChatHandlers (streamHandlers creation and refs:
handleSendMessageRef, handleRetryRef, handleSendMessageWithModelRef,
handleReEdit, handleUseAsReference, handleQueueMessageLoaded), and extract
inputCardProps construction into buildInputCardProps or ChatInputCardContainer
(uses chatState, skillSelector, videoModelSelection/imageModelSelection,
generateParams, streamHandlers); keep exported ChatAreaContent that composes
these hooks/components and only contains top-level JSX and small glue logic.
In `@frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx`:
- Around line 170-1201: The hook file has grown >1000 lines and the two large
send handlers (handleSendMessage and handleSendMessageWithModel) contain
duplicated logic and inconsistent team/validation/toast behavior; split this
file by extracting: (1) payload construction logic used before
contextSendMessage (move code that builds contextItems, messageWithQueueContent,
queueAttachmentIds, inboxAttachmentContexts, pendingContexts and final request
body into a helper like buildSendPayload), (2) pending-context/attachment
mapping into a helper like buildPendingContexts, and (3) validation/toast checks
(team selection, repo requirement, attachment upload state) into small functions
like validateSendPreconditions and showSendErrorToast; import these helpers into
useChatStreamHandlers and replace the inline blocks in handleSendMessage and
handleSendMessageWithModel so both use the same shared helpers and maintain
identical validation/messages and keep each function short.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c2b5f9d2-0a5d-422a-96e6-1cf4d9dfa094
📒 Files selected for processing (5)
frontend/src/features/tasks/components/chat/ChatArea.tsxfrontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxfrontend/src/features/tasks/contexts/taskContext.tsxfrontend/src/i18n/locales/en/chat.jsonfrontend/src/i18n/locales/zh-CN/chat.json
✅ Files skipped from review due to trivial changes (2)
- frontend/src/i18n/locales/zh-CN/chat.json
- frontend/src/i18n/locales/en/chat.json
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/features/tasks/contexts/taskContext.tsx
|
|
||
| // Task context | ||
| const { selectedTaskDetail, setSelectedTask, accessDenied } = useTaskContext() | ||
| const { selectedTask, selectedTaskDetail, setSelectedTask, accessDenied } = useTaskContext() |
There was a problem hiding this comment.
Use selectedTask.team_id before task detail resolves.
The fallback is computed, but Case 1 still requires selectedTaskDetail?.id, so a history click can leave selectedTeam unset/old until detail loading finishes. Sync from selectedTask when it matches the URL task ID.
Proposed fix
const detailTeamId = selectedTaskDetail?.team
? typeof selectedTaskDetail.team === 'number'
? selectedTaskDetail.team
: (selectedTaskDetail.team as Team).id
- : selectedTask?.team_id || null
+ : null
+
+ const selectedTaskMatchesUrl =
+ taskIdFromUrl && selectedTask?.id.toString() === taskIdFromUrl
+
+ if (selectedTaskMatchesUrl && selectedTask.team_id) {
+ const teamFromTask = filteredTeams.find(t => t.id === selectedTask.team_id)
+ if (
+ teamFromTask &&
+ (lastSyncedTaskIdRef.current !== selectedTask.id ||
+ selectedTeam?.id !== selectedTask.team_id)
+ ) {
+ handleTeamChange(teamFromTask)
+ lastSyncedTaskIdRef.current = selectedTask.id
+ hasInitializedTeamRef.current = true
+ return
+ }
+ }
// Case 1: Sync from task detail (HIGHEST PRIORITY)Also applies to: 316-327, 392-400
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@frontend/src/features/tasks/components/chat/ChatArea.tsx` at line 119, The
bug is that selectedTeam can remain unset when a user clicks history because the
component waits for selectedTaskDetail?.id; update the selection logic in
ChatArea to fall back to selectedTask.team_id whenever selectedTask exists and
its id equals the task id from the URL (route param) so the team is synced
immediately while details load. Locate the places using selectedTaskDetail?.id
(e.g., the current fallback computation and the blocks around the earlier
mention and lines ~316-327 and ~392-400) and change them to check for
selectedTaskDetail?.id OR (selectedTask && selectedTask.id === urlTaskId &&
selectedTask.team_id) and use selectedTask.team_id to set
selectedTeam/setSelectedTask accordingly.
| // Check if team is selected before sending | ||
| if (!selectedTeam?.id) { | ||
| toast({ | ||
| variant: 'destructive', | ||
| title: t('chat:errors.team_not_selected') || '请选择智能体', | ||
| description: t('chat:errors.team_not_selected_description') || '请从列表中选择一个智能体后开始对话', | ||
| }) | ||
| return | ||
| } |
There was a problem hiding this comment.
Apply the team guard to model-override sends too.
handleSendMessageWithModel can still send team_id: 0 when selectedTeam is missing, so regeneration/model-override sends can bypass the new protection.
Proposed fix
const message = overrideMessage.trim()
if (!message && !shouldHideChatInput) return
+ if (!selectedTeam?.id) {
+ toast({
+ variant: 'destructive',
+ title: t('chat:errors.team_not_selected') || '请选择智能体',
+ description:
+ t('chat:errors.team_not_selected_description') ||
+ '请从列表中选择一个智能体后开始对话',
+ })
+ return
+ }
+
if (!isAttachmentReadyToSend) {
toast({
variant: 'destructive',
title: t('chat:upload.wait_for_upload'),
@@
- team_id: selectedTeam?.id ?? 0,
+ team_id: selectedTeam.id,Also applies to: 938-942
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx` around
lines 455 - 463, The model-override/regeneration path is missing the same team
check and can send team_id: 0; update the send handlers to guard against missing
selectedTeam before sending by reusing the existing check logic (toast + return)
used earlier, specifically add the selectedTeam?.id guard in
handleSendMessageWithModel and in the other send/regenerate handler that
constructs messages for model-override (the same code path referenced around the
other send function), ensuring any send always early-returns with the
destructive toast when selectedTeam is absent instead of sending team_id: 0.
| title: t('chat:errors.team_not_selected') || '请选择智能体', | ||
| description: t('chat:errors.team_not_selected_description') || '请从列表中选择一个智能体后开始对话', |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd -t f "useChatStreamHandlers.tsx"Repository: wecode-ai/Wegent
Length of output: 129
🏁 Script executed:
head -n 850 frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | tail -n +450 | head -n 50Repository: wecode-ai/Wegent
Length of output: 1595
🏁 Script executed:
grep -n "handleSendMessage" frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | head -20Repository: wecode-ai/Wegent
Length of output: 728
🏁 Script executed:
# Get the full context around lines 459-460 and dependency array
sed -n '450,470p' frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxRepository: wecode-ai/Wegent
Length of output: 736
🏁 Script executed:
# Look for the useCallback/useMemo hook that defines handleSendMessage and its dependencies
ast-grep --pattern 'const handleSendMessage = useCallback($$$, [$$$])'Repository: wecode-ai/Wegent
Length of output: 40050
🏁 Script executed:
head -n 100 frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | grep -E "import|useTranslation|useUnifiedMessages"Repository: wecode-ai/Wegent
Length of output: 1284
🏁 Script executed:
# Search for all toast calls in the file to see if this is a pattern
grep -n "toast({" frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | head -20Repository: wecode-ai/Wegent
Length of output: 325
🏁 Script executed:
# Check if useUnifiedMessages is used elsewhere in this file
grep -n "useUnifiedMessages\|messages" frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | head -20Repository: wecode-ai/Wegent
Length of output: 685
🏁 Script executed:
# Get the full import statement for useTranslation
sed -n '1,50p' frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | grep -A 5 "useTranslation"Repository: wecode-ai/Wegent
Length of output: 422
🏁 Script executed:
# Check how t is used - find the destructuring or usage
grep -n "const.*=.*useTranslation\|const.*t.*=" frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | head -5Repository: wecode-ai/Wegent
Length of output: 248
🏁 Script executed:
# Search for where t is actually initialized in the hook
sed -n '100,200p' frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxRepository: wecode-ai/Wegent
Length of output: 3029
🏁 Script executed:
# Verify if there are other useCallback hooks with t() usage in the file
grep -B 10 "t('chat:" frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | grep -E "useCallback|t\(" | head -20Repository: wecode-ai/Wegent
Length of output: 610
🏁 Script executed:
# Check the specific lines 764-804 to see the full dependency array
sed -n '764,804p' frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxRepository: wecode-ai/Wegent
Length of output: 977
🏁 Script executed:
# Check if there are ESLint overrides or if react-hooks/exhaustive-deps would catch this
grep -r "exhaustive-deps\|eslint-disable" frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxRepository: wecode-ai/Wegent
Length of output: 42
🏁 Script executed:
# Check other useCallback hooks to see if they also have the same issue with t
grep -B 5 -A 50 "const handleRetry = useCallback" frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | grep -E "useCallback|t\(|^\s*\[" | head -30Repository: wecode-ai/Wegent
Length of output: 299
🏁 Script executed:
# Check for eslint config and react-hooks/exhaustive-deps settings
fd -t f ".eslintrc*|eslint.config.*" frontend/Repository: wecode-ai/Wegent
Length of output: 86
🏁 Script executed:
# Let's see if there's a package.json with eslint setup
head -n 100 package.json | grep -A 10 "eslint"Repository: wecode-ai/Wegent
Length of output: 131
🏁 Script executed:
cat frontend/eslint.config.mjsRepository: wecode-ai/Wegent
Length of output: 1016
🏁 Script executed:
# Look for handleSendMessageWithModel too, which was mentioned in the "Also applies to" comment
grep -B 5 -A 50 "const handleSendMessageWithModel = useCallback" frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | head -80Repository: wecode-ai/Wegent
Length of output: 2008
🏁 Script executed:
# Find the complete handleSendMessageWithModel dependency array
sed -n '814,1050p' frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | grep -n -A 50 "^\s*\[" | head -60Repository: wecode-ai/Wegent
Length of output: 2110
🏁 Script executed:
# Get the complete handleSendMessageWithModel dependency array more precisely
sed -n '1000,1050p' frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxRepository: wecode-ai/Wegent
Length of output: 1189
🏁 Script executed:
# Find createRetryButton useCallback and its dependency array
grep -n "createRetryButton" frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxRepository: wecode-ai/Wegent
Length of output: 205
🏁 Script executed:
# Get the context around createRetryButton
sed -n '390,430p' frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxRepository: wecode-ai/Wegent
Length of output: 1510
🏁 Script executed:
# Double-check handleSendMessage uses t() at other places too
sed -n '450,763p' frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx | grep -n "t('chat:" | head -10Repository: wecode-ai/Wegent
Length of output: 224
🏁 Script executed:
# Verify the full context - where does handleSendMessage end and what's at 764-804
sed -n '800,810p' frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxRepository: wecode-ai/Wegent
Length of output: 498
🏁 Script executed:
# Confirm the exact line where handleSendMessage dependency array starts and ends
sed -n '760,806p' frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsxRepository: wecode-ai/Wegent
Length of output: 1029
Add t to the handleSendMessage dependencies.
The callback uses t() for translating error messages at lines 459-460, but t is missing from the dependency array, which will cause stale translations after language changes and violates react-hooks/exhaustive-deps.
Proposed fix
effectiveDeviceId,
effectiveRequiresWorkspace,
additionalSkills,
+ t,
generateParams,
]📝 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.
| title: t('chat:errors.team_not_selected') || '请选择智能体', | |
| description: t('chat:errors.team_not_selected_description') || '请从列表中选择一个智能体后开始对话', | |
| effectiveDeviceId, | |
| effectiveRequiresWorkspace, | |
| additionalSkills, | |
| t, | |
| generateParams, | |
| ] |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@frontend/src/features/tasks/components/chat/useChatStreamHandlers.tsx` around
lines 459 - 460, The handleSendMessage callback uses the i18n translator t() for
error messages but t is not included in its dependency array, causing stale
translations and an exhaustive-deps lint violation; update the dependency array
of handleSendMessage to include t (the i18n translate function) so the callback
is recreated when the language changes, ensuring lines that call
t('chat:errors.team_not_selected') and
t('chat:errors.team_not_selected_description') use current translations.
Summary
修复历史聊天无法继续聊天的问题。
问题原因
当用户点击历史任务继续聊天时,如果 WebSocket 未连接,任务房间不会被加入。当 WebSocket 后续连接时,没有逻辑重新加入任务房间,导致聊天功能无法正常工作。
具体流程:
修复方案
添加独立的 useEffect 监控 WebSocket 连接状态 (isConnected),当连接恢复且存在选中的任务时,自动重新加入任务房间。
joinTask 函数内部已有 deduplication 逻辑 (joinedTasksRef),所以多次调用是安全的。
变更内容
测试计划
Summary by CodeRabbit
Bug Fixes
New Features
Documentation