4343 </div >
4444 </div >
4545 <div class =" header__right" >
46+ <!-- AgentState 显示按钮 - 只在智能体支持 todo 或 files 能力时显示 -->
47+ <AgentPopover
48+ v-model:visible =" agentStatePopoverVisible"
49+ :agent-state =" currentAgentState"
50+ >
51+ <div
52+ class =" agent-nav-btn agent-state-btn"
53+ :class =" { 'has-content': hasAgentStateContent }"
54+ :title =" hasAgentStateContent ? '查看工作状态' : '暂无工作状态'"
55+ >
56+ <Activity class =" nav-btn-icon" size =" 18" />
57+ <span v-if =" hasAgentStateContent" class =" text" >{{ totalAgentStateItems }}</span >
58+ </div >
59+ </AgentPopover >
4660 <!-- <div class="nav-btn" @click="shareChat" v-if="currentChatId && currentAgent">
4761 <ShareAltOutlined style="font-size: 18px;"/>
4862 </div> -->
202216 </div >
203217 </div >
204218 </div >
205- </div >
219+
220+ </div >
206221</template >
207222
208223<script setup>
@@ -217,7 +232,7 @@ import AgentMessageComponent from '@/components/AgentMessageComponent.vue'
217232import ImagePreviewComponent from ' @/components/ImagePreviewComponent.vue'
218233import ChatSidebarComponent from ' @/components/ChatSidebarComponent.vue'
219234import RefsComponent from ' @/components/RefsComponent.vue'
220- import { PanelLeftOpen , MessageCirclePlus , LoaderCircle } from ' lucide-vue-next' ;
235+ import { PanelLeftOpen , MessageCirclePlus , LoaderCircle , Activity } from ' lucide-vue-next' ;
221236import { handleChatError , handleValidationError } from ' @/utils/errorHandler' ;
222237import { ScrollController } from ' @/utils/scrollController' ;
223238import { AgentValidator } from ' @/utils/agentValidator' ;
@@ -228,6 +243,7 @@ import { MessageProcessor } from '@/utils/messageProcessor';
228243import { agentApi , threadApi } from ' @/apis' ;
229244import HumanApprovalModal from ' @/components/HumanApprovalModal.vue' ;
230245import { useApproval } from ' @/composables/useApproval' ;
246+ import AgentPopover from ' @/components/AgentPopover.vue' ;
231247
232248// ==================== PROPS & EMITS ====================
233249const props = defineProps ({
@@ -293,6 +309,9 @@ const attachmentState = reactive({
293309 isUploading: false ,
294310})
295311
312+ // AgentState Popover 状态
313+ const agentStatePopoverVisible = ref (false );
314+
296315// ==================== COMPUTED PROPERTIES ====================
297316const currentAgentId = computed (() => {
298317 if (props .singleMode ) {
@@ -333,6 +352,37 @@ const supportsFileUpload = computed(() => {
333352 const capabilities = currentAgent .value .capabilities || [];
334353 return capabilities .includes (' file_upload' );
335354});
355+ const supportsTodo = computed (() => {
356+ if (! currentAgent .value ) return false ;
357+ const capabilities = currentAgent .value .capabilities || [];
358+ return capabilities .includes (' todo' );
359+ });
360+
361+ const supportsFiles = computed (() => {
362+ if (! currentAgent .value ) return false ;
363+ const capabilities = currentAgent .value .capabilities || [];
364+ return capabilities .includes (' files' );
365+ });
366+
367+ // AgentState 相关计算属性
368+ const currentAgentState = computed (() => {
369+ return currentChatId .value ? getThreadState (currentChatId .value )? .agentState || null : null ;
370+ });
371+
372+ const hasAgentStateContent = computed (() => {
373+ const agentState = currentAgentState .value ;
374+ if (! agentState) return false ;
375+ return (agentState .todos && agentState .todos .length > 0 ) ||
376+ (agentState .files && Object .keys (agentState .files ).length > 0 );
377+ });
378+
379+ const totalAgentStateItems = computed (() => {
380+ const agentState = currentAgentState .value ;
381+ if (! agentState) return 0 ;
382+ const todoCount = agentState .todos ? agentState .todos .length : 0 ;
383+ const fileCount = agentState .files ? Object .keys (agentState .files ).length : 0 ;
384+ return todoCount + fileCount;
385+ });
336386
337387const currentThreadMessages = computed (() => threadMessages .value [currentChatId .value ] || []);
338388
@@ -427,7 +477,7 @@ onMounted(() => {
427477onUnmounted (() => {
428478 if (resizeObserver) resizeObserver .disconnect ();
429479 scrollController .cleanup ();
430- // 清理所有线程状态
480+ // 清理所有线程状态
431481 resetOnGoingConv ();
432482});
433483
@@ -439,7 +489,8 @@ const getThreadState = (threadId) => {
439489 chatState .threadStates [threadId] = {
440490 isStreaming: false ,
441491 streamAbortController: null ,
442- onGoingConv: createOnGoingConvState ()
492+ onGoingConv: createOnGoingConvState (),
493+ agentState: null // 添加 agentState 字段
443494 };
444495 }
445496 return chatState .threadStates [threadId];
@@ -548,10 +599,27 @@ const _processStreamChunk = (chunk, threadId) => {
548599 case ' human_approval_required' :
549600 // 使用审批 composable 处理审批请求
550601 return processApprovalInStream (chunk, threadId, currentAgentId .value );
602+ case ' agent_state' :
603+ if ((supportsTodo .value || supportsFiles .value ) && chunk .agent_state ) {
604+ console .log (' [AgentState]' , {
605+ threadId,
606+ todos: chunk .agent_state ? .todos || [],
607+ files: chunk .agent_state ? .files || []
608+ });
609+ threadState .agentState = chunk .agent_state ;
610+ }
611+ return false ;
551612 case ' finished' :
552613 // 先标记流式结束,但保持消息显示直到历史记录加载完成
553614 if (threadState) {
554615 threadState .isStreaming = false ;
616+ if ((supportsTodo .value || supportsFiles .value ) && threadState .agentState ) {
617+ console .log (' [AgentState|Final]' , {
618+ threadId,
619+ todos: threadState .agentState ? .todos || [],
620+ files: threadState .agentState ? .files || []
621+ });
622+ }
555623 }
556624 // 异步加载历史记录,保持当前消息显示直到历史记录加载完成
557625 fetchThreadMessages ({ agentId: currentAgentId .value , threadId: threadId })
@@ -1231,6 +1299,7 @@ const loadChatsList = async () => {
12311299 }
12321300};
12331301
1302+
12341303const initAll = async () => {
12351304 try {
12361305 if (! agentStore .isInitialized ) {
@@ -1244,7 +1313,7 @@ const initAll = async () => {
12441313onMounted (async () => {
12451314 await initAll ();
12461315 scrollController .enableAutoScroll ();
1247- });
1316+ });
12481317
12491318watch (currentAgentId, async (newAgentId , oldAgentId ) => {
12501319 if (newAgentId !== oldAgentId) {
@@ -1769,6 +1838,16 @@ watch(conversations, () => {
17691838 }
17701839}
17711840
1841+ /* AgentState 按钮有内容时的样式 */
1842+ .agent - nav- btn .agent - state- btn .has - content {
1843+ color: var (-- main- 600 );
1844+
1845+ & : hover: not (.is - disabled ) {
1846+ color: var (-- main- 700 );
1847+ background- color: var (-- main- 40 );
1848+ }
1849+ }
1850+
17721851@keyframes spin {
17731852 from {
17741853 transform: rotate (0deg );
0 commit comments