diff --git a/web/src/components/AgentChatComponent.vue b/web/src/components/AgentChatComponent.vue index 190090f5..cc8c831e 100644 --- a/web/src/components/AgentChatComponent.vue +++ b/web/src/components/AgentChatComponent.vue @@ -220,127 +220,215 @@
-
-
- 待办 +
+
-
-
-
- - - - - -
-
- {{ todo.content }} + +
+
+
+
+ + + + + +
+
+ {{ todo.content }} +
+
暂无待办
-
暂无待办
-
-
- 附件/文件 +
+
-
-
- -
-
{{ file.name }}
-
{{ file.meta || file.path }}
+ +
+
+
+ +
+
{{ file.name }}
+
{{ file.meta || file.path }}
+
+
暂无附件或文件
-
暂无附件或文件
-
-
- 产物 +
+ +
+
+ +
+
暂无产物
-
- -
-
暂无产物
-
-
- 子智能体 - -
-
-
- + +
+
+
+ + +
+
+ {{ getSubagentRunName(run) }} + + + +
+
+ {{ run.description || getSubagentRunMeta(run) }} +
+
暂无子智能体运行
-
暂无子智能体运行
@@ -351,7 +439,8 @@ @@ -370,7 +459,7 @@ import { onDeactivated } from 'vue' import { message } from 'ant-design-vue' -import { RefreshCw, SquareCheck } from 'lucide-vue-next' +import { ChevronDown, RefreshCw, SquareCheck } from 'lucide-vue-next' import { formatFileSize } from '@/utils/file_utils' import FileTypeIcon from '@/components/common/FileTypeIcon.vue' import { generatePixelAvatar } from '@/utils/pixelAvatar' @@ -480,6 +569,12 @@ const threadFilesMap = ref({}) const threadAttachmentsMap = ref({}) const attachmentUploadModalOpen = ref(false) const isRefreshingState = ref(false) +const collapsedStateSections = reactive({ + todos: false, + files: false, + artifacts: false, + subagents: false +}) const threadConfigNoticeMap = ref({}) const threadPendingConfigNoticeMap = ref({}) const threadConfigSnapshotMap = ref({}) @@ -787,14 +882,20 @@ const currentSubagentOptionBySlug = computed(() => { const subagentThreadModal = reactive({ open: false, childThreadId: '', - subagentName: '' + subagentName: '', + subagentAvatar: '' }) const openSubagentThread = (run) => { if (!run?.child_thread_id) return subagentThreadModal.childThreadId = String(run.child_thread_id) subagentThreadModal.subagentName = getSubagentRunName(run) + subagentThreadModal.subagentAvatar = getSubagentIconSrc(run) subagentThreadModal.open = true } +const isStateSectionExpanded = (key) => !collapsedStateSections[key] +const toggleStateSection = (key) => { + collapsedStateSections[key] = !collapsedStateSections[key] +} const currentStateFiles = computed(() => { const files = [] const seenPaths = new Set() @@ -988,6 +1089,25 @@ const displaySubagentRuns = computed(() => { return merged }) +const activeSubagentThreadRun = computed(() => { + if (!subagentThreadModal.childThreadId) return null + return ( + displaySubagentRuns.value.find( + (run) => String(run?.child_thread_id || '') === subagentThreadModal.childThreadId + ) || null + ) +}) +const activeSubagentThreadName = computed(() => + activeSubagentThreadRun.value + ? getSubagentRunName(activeSubagentThreadRun.value) + : subagentThreadModal.subagentName +) +const activeSubagentThreadAvatar = computed(() => + activeSubagentThreadRun.value + ? getSubagentIconSrc(activeSubagentThreadRun.value) || subagentThreadModal.subagentAvatar + : subagentThreadModal.subagentAvatar +) + // 首次运行的子智能体:前端按后端同样的哈希推算 child_thread_id,缓存到映射里供面板/轨迹定位。 watch( onGoingConvMessages, @@ -2858,13 +2978,45 @@ watch(currentChatId, (threadId, oldThreadId) => { display: flex; flex-direction: column; gap: 8px; + + &.is-collapsed { + gap: 0; + } } .state-section-header { + width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px; + padding: 2px 0; + border: none; + border-radius: 6px; + background: transparent; + color: inherit; + font: inherit; + text-align: left; + cursor: pointer; + + &:hover { + .state-section-title, + .state-section-chevron { + color: var(--gray-900); + } + } + + &:focus-visible { + outline: 2px solid var(--main-200); + outline-offset: 2px; + } +} + +.state-section-label { + min-width: 0; + display: inline-flex; + align-items: center; + gap: 4px; } .state-section-title { @@ -2873,6 +3025,22 @@ watch(currentChatId, (threadId, oldThreadId) => { color: var(--gray-800); } +.state-section-chevron { + flex-shrink: 0; + color: var(--gray-500); + transition: + transform 0.18s ease, + color 0.18s ease; + + &.is-collapsed { + transform: rotate(-90deg); + } +} + +.state-section-content { + min-width: 0; +} + .state-section-empty { padding: 10px 12px; border-radius: 10px; diff --git a/web/src/components/SubagentThreadModal.vue b/web/src/components/SubagentThreadModal.vue index 1b39caef..77594b1b 100644 --- a/web/src/components/SubagentThreadModal.vue +++ b/web/src/components/SubagentThreadModal.vue @@ -1,12 +1,23 @@