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()