diff --git a/apps/electron/src/renderer/atoms/agent-atoms.ts b/apps/electron/src/renderer/atoms/agent-atoms.ts index 8adf7b4aa..22d316bf5 100644 --- a/apps/electron/src/renderer/atoms/agent-atoms.ts +++ b/apps/electron/src/renderer/atoms/agent-atoms.ts @@ -515,15 +515,6 @@ export const agentStartedAtAtom = atom((get) => { return get(agentStreamingStatesAtom).get(currentId)?.startedAt }) -export const agentRunningSessionIdsAtom = atom>((get) => { - const states = get(agentStreamingStatesAtom) - const ids = new Set() - for (const [id, state] of states) { - if (state.running) ids.add(id) - } - return ids -}) - /** 侧边栏会话指示点状态 */ export type SessionIndicatorStatus = 'idle' | 'running' | 'blocked' | 'completed' @@ -555,6 +546,10 @@ export const dockBadgeCountAtom = atom((get) => { /** * 每个会话的指示点状态(只包含非 idle 的会话) * 优先级:blocked > running > completed > idle + * + * backgroundWaiting 状态(后台任务运行中、主循环已空闲)也映射为 'running', + * 与真运行态同态显示蓝色脉冲——侧边栏与 Tab 不区分两者; + * AgentView 输入区通过独立的 backgroundWaiting 徽章做差异化提示。 */ export const agentSessionIndicatorMapAtom = atom>((get) => { const streamStates = get(agentStreamingStatesAtom) @@ -566,7 +561,7 @@ export const agentSessionIndicatorMapAtom = atom() for (const [id, state] of streamStates) { - if (!state.running) continue + if (!state.running && !state.backgroundWaiting) continue const hasBlock = (pendingPerms.get(id)?.length ?? 0) > 0 || (pendingAskUser.get(id)?.length ?? 0) > 0 || (pendingExitPlan.get(id)?.length ?? 0) > 0 diff --git a/apps/electron/src/renderer/atoms/tab-atoms.ts b/apps/electron/src/renderer/atoms/tab-atoms.ts index d10300528..963062eec 100644 --- a/apps/electron/src/renderer/atoms/tab-atoms.ts +++ b/apps/electron/src/renderer/atoms/tab-atoms.ts @@ -12,7 +12,6 @@ import { streamingConversationIdsAtom, } from './chat-atoms' import { - agentRunningSessionIdsAtom, agentSessionIndicatorMapAtom, unviewedCompletedSessionIdsAtom, } from './agent-atoms' @@ -141,14 +140,15 @@ export const activeSessionIdAtom = atom((get) => { export const tabStreamingMapAtom = atom>((get) => { const tabs = get(tabsAtom) const chatStreaming = get(streamingConversationIdsAtom) - const agentRunning = get(agentRunningSessionIdsAtom) + const agentIndicator = get(agentSessionIndicatorMapAtom) const map = new Map() for (const tab of tabs) { if (tab.type === 'scratch') continue if (tab.type === 'chat') { map.set(tab.id, chatStreaming.has(tab.sessionId)) } else if (tab.type === 'agent') { - map.set(tab.id, agentRunning.has(tab.sessionId)) + const status = agentIndicator.get(tab.sessionId) + map.set(tab.id, status === 'running' || status === 'blocked') } } return map diff --git a/apps/electron/src/renderer/components/agent/AgentView.tsx b/apps/electron/src/renderer/components/agent/AgentView.tsx index 145e10356..401d744b0 100644 --- a/apps/electron/src/renderer/components/agent/AgentView.tsx +++ b/apps/electron/src/renderer/components/agent/AgentView.tsx @@ -17,7 +17,7 @@ import * as React from 'react' import { unstable_batchedUpdates } from 'react-dom' import { useAtom, useAtomValue, useSetAtom, useStore } from 'jotai' import { toast } from 'sonner' -import { Bot, CornerDownLeft, Square, Settings, Paperclip, FolderPlus, X, Copy, Check, Brain, Sparkles, Eye } from 'lucide-react' +import { Bot, CornerDownLeft, Square, Settings, Paperclip, FolderPlus, X, Copy, Check, Brain, Sparkles, Eye, Loader2 } from 'lucide-react' import { AgentMessages } from './AgentMessages' import { AgentHeader } from './AgentHeader' import { ContextUsageBadge } from './ContextUsageBadge' @@ -2051,6 +2051,9 @@ export function AgentView({ sessionId }: { sessionId: string }): React.ReactElem setProcessGroupsKeepExpanded, ]) + // 后台任务运行中且无输入文本时显示状态标签;用户开始输入后让出位置给 Send 按钮, + // 避免用户在后台任务运行期间无法发送新消息(backgroundWaiting 状态支持注入式发送) + const showBackgroundWaitingBadge = backgroundWaiting && !hasTextInput const inputTrailingNode = streaming && !hasTextInput ? ( @@ -2068,6 +2071,18 @@ export function AgentView({ sessionId }: { sessionId: string }): React.ReactElem

停止 Agent ({getAcceleratorDisplay(getActiveAccelerator('stop-generation'))})

+ ) : showBackgroundWaitingBadge ? ( + + +
+ + 后台任务运行中 +
+
+ +

Agent 正在后台执行任务,您可以继续输入消息

+
+
) : (