From e8a5844af7d916e690a3ed236466d812c1c780f4 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Wed, 24 Dec 2025 20:37:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(todo-tools):=20=E6=B7=BB=E5=8A=A0=E5=BE=85?= =?UTF-8?q?=E5=8A=9E=E4=BA=8B=E9=A1=B9=E7=BB=93=E6=9E=9C=E6=B8=B2=E6=9F=93?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=B9=B6=E4=BC=98=E5=8C=96=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加 TodoListResult 组件用于渲染待办事项结果 使用 ant-design 图标替换原有 SVG 图标以保持一致性 优化待办事项状态显示样式 --- web/src/components/AgentPopover.vue | 81 ++++-------- .../ToolCallingResult/TodoListResult.vue | 118 ++++++++++++++++++ .../ToolCallingResult/ToolResultRenderer.vue | 61 +++++++++ 3 files changed, 201 insertions(+), 59 deletions(-) create mode 100644 web/src/components/ToolCallingResult/TodoListResult.vue diff --git a/web/src/components/AgentPopover.vue b/web/src/components/AgentPopover.vue index 0fb8e197..83ea1bca 100644 --- a/web/src/components/AgentPopover.vue +++ b/web/src/components/AgentPopover.vue @@ -39,17 +39,13 @@ :key="index" class="todo-item" > - - - - - - - - - - - +
+ + + + + +
{{ todo.content }} @@ -110,6 +106,13 @@ + + diff --git a/web/src/components/ToolCallingResult/ToolResultRenderer.vue b/web/src/components/ToolCallingResult/ToolResultRenderer.vue index 86a37940..0058622c 100644 --- a/web/src/components/ToolCallingResult/ToolResultRenderer.vue +++ b/web/src/components/ToolCallingResult/ToolResultRenderer.vue @@ -19,6 +19,12 @@ ref="graphResultRef" /> + + + { return props.resultContent }) +const todoListData = computed(() => { + if (props.toolName !== 'write_todos') return [] + + const raw = props.resultContent + + // 1. Try from parsedData (JSON object) + const data = parsedData.value + if (data && typeof data === 'object') { + if (Array.isArray(data)) return data + if (data.todos && Array.isArray(data.todos)) return data.todos + } + + // 2. Try parsing string if it matches specific pattern + if (typeof raw === 'string') { + let str = raw + if (str.startsWith('Updated todo list to ')) { + str = str.replace('Updated todo list to ', '') + } + + // Try regex parsing for Python-like string + const items = [] + // Matches {'content': '...', 'status': '...'} with escaped quotes support + // content might contain escaped quotes + const contentRegex = /'content':\s*'((?:[^'\\]|\\.)*)'/ + const statusRegex = /'status':\s*'((?:[^'\\]|\\.)*)'/ + + // Split by "}, {" roughly, or just look for objects + // Since it is a list of dicts, we can match individual dicts + const dictRegex = /\{.*?\}/g + const dictMatches = str.match(dictRegex) + + if (dictMatches) { + for (const dictStr of dictMatches) { + const contentMatch = dictStr.match(contentRegex) + const statusMatch = dictStr.match(statusRegex) + + if (contentMatch && statusMatch) { + items.push({ + content: contentMatch[1].replace(/\\'/g, "'").replace(/\\\\/g, "\\"), + status: statusMatch[1] + }) + } + } + } + if (items.length > 0) return items + } + + return [] +}) + +const isTodoListResult = computed(() => { + return props.toolName === 'write_todos' && todoListData.value.length > 0 +}) + // 判断是否为网页搜索结果 const isWebSearchResult = computed(() => { const toolNameLower = props.toolName.toLowerCase()