feat(chat): 调整聊天首页智能体切换入口,优化多智能体场景下的展示逻辑 Fixes: Error:智能体显示有误
Fixes #641
This commit is contained in:
parent
c47a019270
commit
dda3009611
@ -33,6 +33,7 @@
|
||||
|
||||
### 修复
|
||||
|
||||
- 调整聊天首页的智能体切换入口:在无历史对话时,智能体数量 `<= 3` 且 `chat-main` 宽度不小于 `380px` 时继续使用横向 segmented;当智能体数量 `>= 4` 或内容区宽度小于 `380px` 时自动收敛为“当前智能体 + 下拉按钮”形式,避免多智能体或窄屏场景下入口被截断
|
||||
- 发布前一致性修复:统一 0.6.0 版本号(backend/package/web)、更新 dev/prod 镜像标签语义(`0.6.0.dev` / `0.6.0`),并为 `/api/system/health` 补充 `version` 字段,提升部署可观测性与发版追溯能力
|
||||
- 收敛“状态工作台”自动弹出规则:前端不再因为共享 `workspace` 或文件系统天然存在内容而默认展开,改为仅在 `/home/gem/user-data/uploads` 或 `/home/gem/user-data/outputs` 下检测到实际文件时自动弹出;手动打开、关闭、刷新和伸缩交互保持不变
|
||||
- 调整智能体 todo 展示语义:待办状态不再作为 `capabilities` 前端开关,而是直接根据运行态 `agent_state.todos` 渲染;同时将 todo 入口从 Agent Panel 移到输入框内的轻量浮层,并让右侧“状态工作台”收敛为文件系统视图,输入框按钮文案同步由“状态”调整为“文件”
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
- 重写界面设计规范:参考 `DESIGN.md` 写法补充视觉气质、颜色 token、组件状态、布局层级、响应式与 Agent Prompt Guide,并基于该规范收敛首页视觉表现,移除装饰性渐变、重阴影、hover 位移和入场动画。
|
||||
- 修复对话摘要中间件的工具结果卸载链路:摘要触发时改为将大体积 `ToolMessage` 写入当前 agent 可见的 sandbox outputs 路径,修正 `summary_offload` 路径拼接错误、`messages` 触发条件下不会真正裁剪历史的问题,并避免将 system message 重复纳入摘要与最终消息列表;补充对应单元测试覆盖。
|
||||
- 调整智能体对话中的工具调用展示:连续工具调用默认折叠为“调用了 N 个工具”的轻量摘要,展开后改为弱化时间线样式,减少工具结果卡片对正文阅读节奏的干扰。
|
||||
- 调整聊天首页的智能体切换入口:在无历史对话时,智能体数量 `<= 3` 且 `chat-main` 宽度不小于 `380px` 时继续使用横向 segmented;当智能体数量 `>= 4` 或内容区宽度小于 `380px` 时自动收敛为“当前智能体 + 下拉按钮”形式。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -153,6 +153,37 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-else-if="showStartAgentDropdown" class="agent-switcher-wrapper">
|
||||
<a-dropdown :trigger="['click']" placement="bottomCenter">
|
||||
<button type="button" class="agent-switcher-btn">
|
||||
<component :is="currentAgentIcon" size="16" class="agent-switcher-icon" />
|
||||
<span class="agent-switcher-text">{{ currentAgentName }}</span>
|
||||
<ChevronDown size="16" class="agent-switcher-chevron" />
|
||||
</button>
|
||||
<template #overlay>
|
||||
<a-menu class="agent-switcher-menu">
|
||||
<a-menu-item
|
||||
v-for="agent in startAgents"
|
||||
:key="agent.id"
|
||||
@click="handleStartAgentChange(agent.id)"
|
||||
>
|
||||
<div class="agent-switcher-menu-item">
|
||||
<component
|
||||
:is="getAgentIconComponent(agent.id)"
|
||||
size="16"
|
||||
class="agent-switcher-menu-icon"
|
||||
/>
|
||||
<span class="agent-switcher-menu-text">{{ agent.name || 'Unknown' }}</span>
|
||||
<span v-if="agent.id === currentAgentId" class="agent-switcher-menu-badge">
|
||||
当前
|
||||
</span>
|
||||
</div>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
|
||||
<AgentArtifactsCard
|
||||
:artifacts="currentArtifacts"
|
||||
:thread-id="currentChatId"
|
||||
@ -247,7 +278,14 @@ import AgentMessageComponent from '@/components/AgentMessageComponent.vue'
|
||||
import ChatSidebarComponent from '@/components/ChatSidebarComponent.vue'
|
||||
import RefsComponent from '@/components/RefsComponent.vue'
|
||||
import ToolCallsGroupComponent from '@/components/ToolCallsGroupComponent.vue'
|
||||
import { PanelLeftOpen, MessageCirclePlus, LoaderCircle, Bot, Telescope } from 'lucide-vue-next'
|
||||
import {
|
||||
PanelLeftOpen,
|
||||
MessageCirclePlus,
|
||||
LoaderCircle,
|
||||
Bot,
|
||||
Telescope,
|
||||
ChevronDown
|
||||
} from 'lucide-vue-next'
|
||||
import { handleChatError, handleValidationError } from '@/utils/errorHandler'
|
||||
import { ScrollController } from '@/utils/scrollController'
|
||||
import { AgentValidator } from '@/utils/agentValidator'
|
||||
@ -359,7 +397,8 @@ const threadAttachmentsMap = ref({})
|
||||
|
||||
// 本地 UI 状态(仅在本组件使用)
|
||||
const localUIState = reactive({
|
||||
isInitialRender: true
|
||||
isInitialRender: true,
|
||||
chatMainWidth: typeof window !== 'undefined' ? window.innerWidth : 0
|
||||
})
|
||||
|
||||
// Agent Panel State
|
||||
@ -392,6 +431,7 @@ const currentAgent = computed(() => {
|
||||
if (!currentAgentId.value || !agents.value || !agents.value.length) return null
|
||||
return agents.value.find((a) => a.id === currentAgentId.value) || null
|
||||
})
|
||||
const startAgents = computed(() => agents.value || [])
|
||||
const chatsList = computed(() => threads.value || [])
|
||||
const currentChatId = computed(() => chatState.currentThreadId)
|
||||
const currentThread = computed(() => {
|
||||
@ -409,6 +449,7 @@ const currentThreadAgentName = computed(() => {
|
||||
}
|
||||
return currentAgentName.value
|
||||
})
|
||||
const currentAgentIcon = computed(() => getAgentIconComponent(currentAgentId.value))
|
||||
|
||||
// 检查当前智能体是否支持文件上传
|
||||
const supportsFileUpload = computed(() => {
|
||||
@ -530,7 +571,7 @@ const getAgentIconComponent = (agentId) => {
|
||||
}
|
||||
|
||||
const agentSegmentOptions = computed(() => {
|
||||
return (agents.value || []).map((agent) => {
|
||||
return startAgents.value.map((agent) => {
|
||||
const IconComponent = getAgentIconComponent(agent.id)
|
||||
return {
|
||||
label: () =>
|
||||
@ -543,8 +584,16 @@ const agentSegmentOptions = computed(() => {
|
||||
})
|
||||
})
|
||||
|
||||
const showStartAgentSelector = computed(() => {
|
||||
return !props.singleMode && !conversations.value.length && startAgents.value.length > 1
|
||||
})
|
||||
|
||||
const showStartAgentDropdown = computed(() => {
|
||||
return showStartAgentSelector.value && (startAgents.value.length >= 4 || localUIState.chatMainWidth < 380)
|
||||
})
|
||||
|
||||
const showStartAgentSegment = computed(() => {
|
||||
return !props.singleMode && !conversations.value.length && agentSegmentOptions.value.length > 1
|
||||
return showStartAgentSelector.value && !showStartAgentDropdown.value
|
||||
})
|
||||
|
||||
const handleStartAgentChange = async (agentId) => {
|
||||
@ -594,9 +643,11 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
if (window.ResizeObserver && chatMainRef.value) {
|
||||
localUIState.chatMainWidth = chatMainRef.value.clientWidth || window.innerWidth
|
||||
chatMainResizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
const width = entry.contentRect.width
|
||||
localUIState.chatMainWidth = width
|
||||
const isTakingSpace = chatUIStore.isSidebarOpen && !isSidebarFloating.value
|
||||
|
||||
if (isTakingSpace) {
|
||||
@ -1969,6 +2020,80 @@ watch(currentChatId, (threadId, oldThreadId) => {
|
||||
}
|
||||
}
|
||||
|
||||
.agent-switcher-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 0 auto 18px;
|
||||
}
|
||||
|
||||
.agent-switcher-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
padding: 4px 12px;
|
||||
border: 1px solid var(--gray-150);
|
||||
border-radius: 8px;
|
||||
background: var(--gray-0);
|
||||
color: var(--gray-900);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color 0.2s ease,
|
||||
border-color 0.2s ease,
|
||||
color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: var(--gray-0);
|
||||
border-color: var(--gray-200);
|
||||
}
|
||||
}
|
||||
|
||||
.agent-switcher-icon,
|
||||
.agent-switcher-chevron {
|
||||
flex-shrink: 0;
|
||||
color: var(--gray-600);
|
||||
}
|
||||
|
||||
.agent-switcher-text {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:deep(.agent-switcher-menu) {
|
||||
min-width: 220px;
|
||||
}
|
||||
|
||||
:deep(.agent-switcher-menu-item) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
:deep(.agent-switcher-menu-icon) {
|
||||
flex-shrink: 0;
|
||||
color: var(--gray-600);
|
||||
}
|
||||
|
||||
:deep(.agent-switcher-menu-text) {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:deep(.agent-switcher-menu-badge) {
|
||||
flex-shrink: 0;
|
||||
padding: 1px 8px;
|
||||
border-radius: 999px;
|
||||
background: var(--main-30);
|
||||
color: var(--main-700);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.example-questions {
|
||||
margin-top: 16px;
|
||||
text-align: center;
|
||||
@ -2184,6 +2309,15 @@ watch(currentChatId, (threadId, oldThreadId) => {
|
||||
}
|
||||
}
|
||||
|
||||
.agent-switcher-wrapper {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.agent-switcher-btn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
.header__left {
|
||||
.text {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user