Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/en/developer-guide/wework-chat-state-sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ The goal bar's running presentation must be constrained by the current runtime t
- This derivation affects only Wework presentation and elapsed-time calculation; it does not automatically call the goal pause API. Persisting `paused` remains an explicit user action through **Pause goal**.
- When the task reports `running: true` again, the goal uses the original status returned by the runtime goal API.

## Composer Mode Indicators

When the composer is in plan mode or goal-draft mode, its bottom mode pill must show a semantic icon to the left of its label: a checklist for plan mode and a target for goal draft. Desktop and compact layouts must reuse the same mode-pill implementation so the state is expressed consistently.

The mode pill's cancel button appears only on hover and is absolutely positioned over the left icon while that icon fades out. Do not expand the cancel button or add spacing that changes the pill width, because that causes the label to shift horizontally.

## Long Output Memory Boundary

The Wework chat UI must not keep complete long-running output in React state. `WorkbenchMessage.content`, thinking/text/plan block `content`, and tool block `toolOutput` must enter `messages` through the shared preview-window path:
Expand Down
6 changes: 6 additions & 0 deletions docs/zh/developer-guide/wework-chat-state-sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ Goal 条的运行态必须受当前 runtime task 的执行快照约束:当 App
- 此派生只影响 Wework 的展示与计时,不会自动调用 goal 暂停接口。用户点击“暂停目标”才会持久化 `paused` 状态。
- 任务重新处于 `running: true` 时,goal 继续使用 runtime goal API 返回的原始状态。

## Composer 模式提示

当 composer 处于计划模式或目标草稿模式时,底部模式胶囊必须在标签左侧显示对应的语义图标:计划模式使用清单图标,目标草稿使用靶心图标。桌面和紧凑布局必须复用同一个模式胶囊实现,确保表达一致。

模式胶囊的取消按钮仅在悬停时显示,并绝对定位覆盖左侧图标;原图标在同一状态下淡出。不要通过展开取消按钮或额外边距改变胶囊宽度,否则标签会发生横向跳动。

## 长输出内存边界

Wework 的聊天 UI 不能把持续输出的完整正文长期保存在 React state 中。`WorkbenchMessage.content`、thinking/text/plan block 的 `content`、tool block 的 `toolOutput` 都必须通过统一的预览窗口进入 `messages`:
Expand Down
13 changes: 7 additions & 6 deletions wework/src/components/chat/ChatInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,10 @@ describe('ChatInput', () => {
expect(pill).toHaveClass('h-7')
expect(pill).toHaveClass('rounded-xl')
expect(pill).toHaveClass('bg-muted')
expect(screen.getByTestId('cancel-plan-mode-button')).toHaveClass('w-0')
expect(screen.getByTestId('cancel-plan-mode-button')).toHaveClass('group-hover:w-5')
expect(screen.getByTestId('plan-mode-pill-icon')).toHaveClass('h-4')
expect(screen.getByTestId('cancel-plan-mode-button')).toHaveClass('absolute')
expect(screen.getByTestId('cancel-plan-mode-button')).toHaveClass('left-2')
expect(screen.getByTestId('plan-mode-pill-icon')).toHaveClass('group-hover:opacity-0')

await userEvent.click(screen.getByTestId('cancel-plan-mode-button'))

Expand Down Expand Up @@ -2270,12 +2272,11 @@ describe('ChatInput', () => {
expect(pill).toHaveClass('justify-center')
expect(pill).toHaveClass('border')
expect(pill).toHaveClass('bg-muted')
expect(screen.getByTestId('goal-draft-pill-icon')).toHaveClass('h-4')
expect(cancelButton).toHaveClass('opacity-0')
expect(cancelButton).toHaveClass('w-0')
expect(cancelButton).toHaveClass('group-hover:w-5')
expect(cancelButton).toHaveClass('group-hover:mr-1.5')
expect(cancelButton).toHaveClass('absolute')
expect(cancelButton).toHaveClass('left-2')
expect(cancelButton).toHaveClass('group-hover:opacity-100')
expect(cancelButton).toHaveClass('group-hover:bg-text-muted/15')
expect(cancelButton).toHaveClass('hover:bg-text-muted/30')

fireEvent.click(cancelButton)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ export function CompactChatComposer({
) : planModeActive ? (
<ComposerModePill
label={t('workbench.plan_mode', '计划模式')}
icon={ClipboardList}
testId="plan-mode-pill"
cancelTestId="cancel-plan-mode-button"
cancelLabel={t('workbench.disable_plan_mode', '关闭计划模式')}
Expand Down
3 changes: 2 additions & 1 deletion wework/src/components/chat/composer/ComposerToolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ArrowUp, Square } from 'lucide-react'
import { ArrowUp, ClipboardList, Square } from 'lucide-react'
import { useTranslation } from '@/hooks/useTranslation'
import type { ModelOptions, RuntimeContextUsage, UnifiedModel } from '@/types/api'
import { AddContextMenu } from './AddContextMenu'
Expand Down Expand Up @@ -71,6 +71,7 @@ export function ComposerToolbar({
) : planModeActive ? (
<ComposerModePill
label={t('workbench.plan_mode', '计划模式')}
icon={ClipboardList}
testId="plan-mode-pill"
cancelTestId="cancel-plan-mode-button"
cancelLabel={t('workbench.disable_plan_mode', '关闭计划模式')}
Expand Down
17 changes: 14 additions & 3 deletions wework/src/components/chat/composer/GoalDraftPill.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CircleX } from 'lucide-react'
import { CircleX, Target } from 'lucide-react'
import type { LucideIcon } from 'lucide-react'
import type { KeyboardEvent } from 'react'
import { useTranslation } from '@/hooks/useTranslation'

Expand All @@ -14,6 +15,7 @@ interface ComposerModePillProps {
disabled?: boolean
className?: string
title?: string
icon?: LucideIcon
}

export function ComposerModePill({
Expand All @@ -28,6 +30,7 @@ export function ComposerModePill({
disabled = false,
className = '',
title,
icon: Icon,
}: ComposerModePillProps) {
const { t } = useTranslation('common')
const interactive = Boolean(onClick)
Expand All @@ -54,7 +57,7 @@ export function ComposerModePill({
}}
onKeyDown={handleKeyDown}
className={[
'group flex h-7 w-fit shrink-0 items-center justify-center rounded-xl border border-border/70 bg-muted px-2.5 text-[13px] font-semibold leading-[18px] text-text-secondary transition-[background-color,color] hover:bg-muted/80 hover:text-text-primary',
'group relative flex h-7 w-fit shrink-0 items-center justify-center rounded-xl border border-border/70 bg-muted px-2.5 text-[13px] font-semibold leading-[18px] text-text-secondary transition-[background-color,color] hover:bg-muted/80 hover:text-text-primary',
interactive && !disabled ? 'cursor-pointer' : '',
disabled ? 'cursor-not-allowed opacity-50' : '',
className,
Expand All @@ -63,6 +66,13 @@ export function ComposerModePill({
.join(' ')}
title={title}
>
{Icon && (
<Icon
data-testid={`${testId}-icon`}
className="mr-1.5 h-4 w-4 shrink-0 transition-opacity group-hover:opacity-0"
aria-hidden="true"
/>
)}
{onCancel && (
<button
type="button"
Expand All @@ -72,7 +82,7 @@ export function ComposerModePill({
onCancel()
}}
disabled={disabled}
className="pointer-events-none flex h-5 w-0 items-center justify-center overflow-hidden rounded-full bg-text-muted/15 text-text-muted opacity-0 transition-[width,margin,opacity,background-color,color] group-hover:pointer-events-auto group-hover:mr-1.5 group-hover:w-5 group-hover:bg-text-muted/15 group-hover:opacity-100 hover:bg-text-muted/30 hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-0"
className="pointer-events-none absolute left-2 flex h-5 w-5 items-center justify-center rounded-full bg-text-muted/15 text-text-muted opacity-0 transition-[opacity,background-color,color] group-hover:pointer-events-auto group-hover:opacity-100 hover:bg-text-muted/30 hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-0"

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use the required compact icon-button size or document an exception.

The cancel button uses h-5 w-5, which conflicts with the Wework control sizing rule requiring icon-only buttons to use h-8 w-8. If the pill’s h-7 layout requires the smaller control, document that exception explicitly.

As per coding guidelines: “Wework desktop workbench controls must use the compact sizing system: buttons h-8, icon-only buttons h-8 w-8.”

🤖 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/GoalDraftPill.tsx` at line 85, The cancel
icon button in GoalDraftPill uses the nonstandard h-5 w-5 size; update its
sizing to the required h-8 w-8 compact icon-button dimensions, or add an
explicit documented exception if the h-7 pill layout cannot accommodate it.

Source: Coding guidelines


🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the target file and nearby context
wc -l wework/src/components/chat/composer/GoalDraftPill.tsx
sed -n '1,220p' wework/src/components/chat/composer/GoalDraftPill.tsx

# Find where this component is used
rg -n "GoalDraftPill|ComposerModePill|CompactChatComposer" wework/src/components wework/src -g '*.ts' -g '*.tsx'

# Inspect the compact composer files mentioned by the review comment
fd -a "CompactChatComposer.tsx|ComposerModePill.tsx|GoalDraftPill.tsx" wework/src

Repository: wecode-ai/Wegent

Length of output: 7500


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,260p' wework/src/components/chat/composer/CompactChatComposer.tsx
printf '\n----\n'
sed -n '1,180p' wework/src/components/chat/composer/ComposerToolbar.tsx
printf '\n----\n'
rg -n "cancel-goal-draft-button|onCancelGoalDraft|cancel_goal_draft|workbench.cancel_mode" wework/src -g '*.ts' -g '*.tsx'

Repository: wecode-ai/Wegent

Length of output: 15863


Make the cancel control reachable without hover.

This shared pill is used in the compact composer, so the cancel button can’t be used on touch devices and becomes an invisible tab stop on keyboard because it only appears on group-hover. Reveal it on focus/non-hover devices, and use the required compact h-8 w-8 icon-button sizing instead of h-5 w-5.

🤖 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/GoalDraftPill.tsx` at line 85, Update the
cancel button styling in GoalDraftPill so it is reachable without hover: use
compact h-8 w-8 icon-button sizing, and make it visible on keyboard focus and
non-hover/touch devices while preserving hover behavior and disabled styling.
Ensure it is not an invisible tab stop when hidden.

aria-label={resolvedCancelLabel}
>
<CircleX className="h-4 w-4 shrink-0" />
Expand All @@ -94,6 +104,7 @@ export function GoalDraftPill({ onCancel, className = '' }: GoalDraftPillProps)
return (
<ComposerModePill
label={t('workbench.goal_chip', '目标')}
icon={Target}
testId="goal-draft-pill"
cancelTestId="cancel-goal-draft-button"
cancelLabel={t('workbench.cancel_goal_draft', '取消目标')}
Expand Down
Loading