Skip to content

fix(wework): restore streaming content after refresh - #1309

Merged
qdaxb merged 1 commit into
wecode-ai:mainfrom
FicoHu:codex/fix-wework-refresh-stream-history
Jun 8, 2026
Merged

qdaxb merged 1 commit into
wecode-ai:mainfrom
FicoHu:codex/fix-wework-refresh-stream-history

Conversation

@FicoHu

@FicoHu FicoHu commented Jun 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Running tasks now restore cached streaming content when reopened after refresh.
  • Improvements

    • Removed voice input functionality from the chat composer.
    • Adjusted sidebar spacing and layout for task rows and project sections.
    • Updated chat composer padding and styling adjustments.
  • Tests

    • Added test coverage for cached streaming content restoration.
    • Updated assertions for sidebar and composer styling changes.

@coderabbitai

coderabbitai Bot commented Jun 8, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR restores cached streaming assistant content when opening a task after refresh, removes voice input UI from the compact composer, and adjusts sidebar spacing. The cached-content restoration dispatches a new assistant_cached action when openTask receives a cached streaming payload from joinTask, with corresponding reducer and test coverage. Voice input removal eliminates the conditional voice button from the composer and toolbar, switches to fixed padding, and cleans up related translations and tests. Sidebar spacing adjustments refine task row and project item alignment.

Changes

Cached content restoration

Layer / File(s) Summary
Message action and reducer for cached content
wework/src/features/workbench/messageReducer.ts
Added assistant_cached to the MessageAction union and implemented reducer logic to update existing or append new assistant messages with cached streaming content and status preserved as 'streaming'.
openTask cached-content dispatch
wework/src/features/workbench/WorkbenchProvider.tsx
openTask now awaits chatStream.joinTask(taskId), checks for joinResponse.streaming, and dispatches assistant_cached with the cached content and subtask id.
Test helper and cached-restore verification
wework/src/features/workbench/WorkbenchProvider.test.tsx
Added TaskMessagesProbe test helper that renders formatted messages and a Vitest that mocks getTaskDetail and chatStream.joinTask to verify cached assistant content is restored when opening a running task.

Voice input removal from composer UI

Layer / File(s) Summary
CompactChatComposer voice input removal
wework/src/components/chat/composer/CompactChatComposer.tsx
Removed Mic icon import, conditional voice input button render, and switched to fixed pr-16 right padding; added explicitLineCount derived from textarea value for expansion logic.
ComposerToolbar voice input removal
wework/src/components/chat/composer/ComposerToolbar.tsx
Removed Mic icon import and voice input button UI branch, leaving pause/send response controls as toolbar actions.
Chat input tests and localization cleanup
wework/src/components/chat/ChatInput.test.tsx, wework/src/i18n/locales/en/common.json, wework/src/i18n/locales/zh-CN/common.json
Updated ChatInput tests to expect pr-16 class and assert voice-input-button is absent; removed voice_input translation key from English and Chinese locale files.

Desktop sidebar spacing adjustments

Layer / File(s) Summary
Sidebar spacing and test update
wework/src/components/layout/DesktopSidebar.tsx, wework/src/components/layout/DesktopWorkbenchLayout.test.tsx
Adjusted ProjectTaskRow padding (pl-10/pr-0.5 → pl-9/pr-1), reduced expanded ProjectItem placeholder and toggle margins (ml-10 → ml-6), and updated toggle padding; updated corresponding test assertion to include pl-9 class.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • wecode-ai/Wegent#1262: Both PRs modify WorkbenchProvider.tsx task restoration flow and openTask invocation related to restoring state after refresh.

Suggested reviewers

  • qdaxb

Poem

🐰 Bouncing through the cached content flow,
Voice buttons fade, but streams still glow,
Spacing tightened, tests aligned,
Refresh restores what users find! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main objective: restoring streaming content after refresh. This is supported by the core changes in WorkbenchProvider.tsx and messageReducer.ts that handle cached streaming content restoration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
wework/src/features/workbench/messageReducer.ts (1)

929-937: ⚡ Quick win

Consider checking for cached_content presence explicitly.

The current condition checks joinResponse?.streaming, but doesn't verify that cached_content exists. Adding an explicit check would make the code more defensive and self-documenting:

🛡️ Suggested defensive check
-      if (joinResponse?.streaming) {
+      if (joinResponse?.streaming?.cached_content) {
         dispatchMessages({
           type: 'assistant_cached',
           taskId,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/features/workbench/messageReducer.ts` around lines 929 - 937, The
condition currently checks joinResponse?.streaming but may access
joinResponse.cached_content without verifying it exists; update the logic in the
messageReducer (the code that handles joinResponse in the reducer function
handling streaming updates) to require joinResponse?.streaming &&
!!joinResponse.cached_content (or a similar explicit null/undefined check)
before using cached_content, ensuring you guard any subsequent access to
joinResponse.cached_content and adjust any early-return or branch handling
accordingly.
wework/src/features/workbench/WorkbenchProvider.tsx (1)

930-937: ⚡ Quick win

Consider validating nested streaming properties before dispatch.

The code checks joinResponse?.streaming but doesn't validate that streaming.subtask_id and streaming.cached_content are defined. If the streaming object exists but these nested properties are missing, the dispatch would pass undefined values to the reducer.

Consider adding explicit checks:

if (joinResponse?.streaming?.subtask_id && joinResponse.streaming.cached_content !== undefined) {
  dispatchMessages({
    type: 'assistant_cached',
    taskId,
    subtaskId: joinResponse.streaming.subtask_id,
    content: joinResponse.streaming.cached_content,
  })
}

Note: Using !== undefined for cached_content allows empty strings to pass through if that's intentional behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/features/workbench/WorkbenchProvider.tsx` around lines 930 - 937,
The current guard only checks joinResponse?.streaming but can still pass
undefined nested fields to dispatchMessages; update the condition around the
dispatch that references joinResponse.streaming.subtask_id and
joinResponse.streaming.cached_content to explicitly verify subtask_id is present
and cached_content !== undefined (so empty strings are allowed), then only call
dispatchMessages({ type: 'assistant_cached', taskId, subtaskId:
joinResponse.streaming.subtask_id, content:
joinResponse.streaming.cached_content }) when those checks pass to avoid sending
undefined values to the reducer.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@wework/src/features/workbench/messageReducer.ts`:
- Around line 929-937: The condition currently checks joinResponse?.streaming
but may access joinResponse.cached_content without verifying it exists; update
the logic in the messageReducer (the code that handles joinResponse in the
reducer function handling streaming updates) to require joinResponse?.streaming
&& !!joinResponse.cached_content (or a similar explicit null/undefined check)
before using cached_content, ensuring you guard any subsequent access to
joinResponse.cached_content and adjust any early-return or branch handling
accordingly.

In `@wework/src/features/workbench/WorkbenchProvider.tsx`:
- Around line 930-937: The current guard only checks joinResponse?.streaming but
can still pass undefined nested fields to dispatchMessages; update the condition
around the dispatch that references joinResponse.streaming.subtask_id and
joinResponse.streaming.cached_content to explicitly verify subtask_id is present
and cached_content !== undefined (so empty strings are allowed), then only call
dispatchMessages({ type: 'assistant_cached', taskId, subtaskId:
joinResponse.streaming.subtask_id, content:
joinResponse.streaming.cached_content }) when those checks pass to avoid sending
undefined values to the reducer.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c3432398-050a-4183-8af1-ab65c7edb17e

📥 Commits

Reviewing files that changed from the base of the PR and between d38e770 and c3babce.

📒 Files selected for processing (3)
  • wework/src/features/workbench/WorkbenchProvider.test.tsx
  • wework/src/features/workbench/WorkbenchProvider.tsx
  • wework/src/features/workbench/messageReducer.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/features/tasks/components/chat/ChatArea.tsx (1)

488-490: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Allow the URL-selected team path to run before the empty-list bailout.

Line 489 returns before the teamId branch executes. When /chat?teamId=... resolves a team through teamApis.getTeam but filteredTeams is still empty, fetchedTeamFromUrl is never applied and the chat falls back to no/default selection instead of the requested team.

Suggested fix
   useEffect(() => {
-    if (filteredTeams.length === 0) return
-
     // Extract team ID from task detail
     const detailTeamId = selectedTaskDetail?.team
       ? typeof selectedTaskDetail.team === 'number'
         ? selectedTaskDetail.team
         : (selectedTaskDetail.team as Team).id
@@
     if (!taskIdFromUrl && parsedTeamIdFromUrl) {
       const teamFromUrl =
         filteredTeams.find(t => t.id === parsedTeamIdFromUrl) ||
         teams.find(t => t.id === parsedTeamIdFromUrl) ||
         (fetchedTeamFromUrl?.id === parsedTeamIdFromUrl ? fetchedTeamFromUrl : null)
       if (teamFromUrl) {
         handleTeamChange(teamFromUrl)
         hasInitializedTeamRef.current = true
         lastSyncedTaskIdRef.current = null
         return
       }
     }
+
+    if (filteredTeams.length === 0) return

Also applies to: 536-540

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/features/tasks/components/chat/ChatArea.tsx` around lines 488 -
490, The early return in the useEffect that checks filteredTeams (in the
ChatArea useEffect) prevents the teamId URL branch from running; update the
effect so the URL-selected team logic (the teamId handling that calls
teamApis.getTeam and sets fetchedTeamFromUrl) executes before or regardless of
the filteredTeams.length bail-out, then only return early after that logic if
appropriate; specifically, move or reorder the teamId / fetchedTeamFromUrl
handling to run prior to the filteredTeams.length === 0 check (or change the
condition to allow the teamId branch to proceed) so fetchedTeamFromUrl is
applied when a team is resolved from the URL.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@frontend/src/features/tasks/components/chat/ChatArea.tsx`:
- Around line 488-490: The early return in the useEffect that checks
filteredTeams (in the ChatArea useEffect) prevents the teamId URL branch from
running; update the effect so the URL-selected team logic (the teamId handling
that calls teamApis.getTeam and sets fetchedTeamFromUrl) executes before or
regardless of the filteredTeams.length bail-out, then only return early after
that logic if appropriate; specifically, move or reorder the teamId /
fetchedTeamFromUrl handling to run prior to the filteredTeams.length === 0 check
(or change the condition to allow the teamId branch to proceed) so
fetchedTeamFromUrl is applied when a team is resolved from the URL.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9683f8c1-4600-4c49-90fe-9c0f38b124ff

📥 Commits

Reviewing files that changed from the base of the PR and between 12677e1 and f188655.

📒 Files selected for processing (3)
  • frontend/e2e/tests/tasks/chat-image-browser-e2e.spec.ts
  • frontend/src/apis/team.ts
  • frontend/src/features/tasks/components/chat/ChatArea.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
wework/src/components/chat/composer/CompactChatComposer.tsx (1)

68-76: 💤 Low value

Refactor: Redundant dependency in useEffect array.

The dependency array includes both explicitLineCount and value, but explicitLineCount is directly derived from value (line 49). This means the effect will run whenever either changes, potentially executing twice per value update. Consider removing value from the dependencies since explicitLineCount already captures the relevant changes.

♻️ Suggested optimization
   useEffect(() => {
     const textarea = textareaRef.current
     if (!textarea) {
       setCanExpandInput(explicitLineCount > 4)
       return
     }
 
     setCanExpandInput(explicitLineCount > 4 || textarea.scrollHeight > 124)
-  }, [explicitLineCount, textareaRef, value])
+  }, [explicitLineCount, textareaRef])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/components/chat/composer/CompactChatComposer.tsx` around lines 68
- 76, The effect in useEffect (which reads textareaRef.current and calls
setCanExpandInput) redundantly lists value in its dependency array even though
explicitLineCount is derived from value; remove value from the dependency array
so the effect depends only on explicitLineCount (and textareaRef if you need the
ref itself) to avoid double runs per value update, keeping the logic in the
effect unchanged and ensuring textareaRef remains a stable ref (use
textareaRef.current inside the effect).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@wework/src/components/chat/composer/CompactChatComposer.tsx`:
- Around line 68-76: The effect in useEffect (which reads textareaRef.current
and calls setCanExpandInput) redundantly lists value in its dependency array
even though explicitLineCount is derived from value; remove value from the
dependency array so the effect depends only on explicitLineCount (and
textareaRef if you need the ref itself) to avoid double runs per value update,
keeping the logic in the effect unchanged and ensuring textareaRef remains a
stable ref (use textareaRef.current inside the effect).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 52a9006c-82fc-4e17-a93d-c1a4c4704cb4

📥 Commits

Reviewing files that changed from the base of the PR and between f188655 and 97a8ed0.

📒 Files selected for processing (5)
  • wework/src/components/chat/ChatInput.test.tsx
  • wework/src/components/chat/composer/CompactChatComposer.tsx
  • wework/src/components/chat/composer/ComposerToolbar.tsx
  • wework/src/i18n/locales/en/common.json
  • wework/src/i18n/locales/zh-CN/common.json
💤 Files with no reviewable changes (2)
  • wework/src/i18n/locales/zh-CN/common.json
  • wework/src/i18n/locales/en/common.json

@FicoHu
FicoHu force-pushed the codex/fix-wework-refresh-stream-history branch from b78f327 to 2b715d2 Compare June 8, 2026 10:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants