diff --git a/backend/app/services/agent/agents/analysis.py b/backend/app/services/agent/agents/analysis.py index 1933ae3..08337d9 100644 --- a/backend/app/services/agent/agents/analysis.py +++ b/backend/app/services/agent/agents/analysis.py @@ -664,7 +664,7 @@ Final Answer: {{"findings": [...], "summary": "..."}}""" await self.emit_llm_decision("继续分析", "LLM 需要更多分析") self._conversation_history.append({ "role": "user", - "content": "请继续分析。你输出了 Thought 但没有输出 Action。请**立即**选择一个工具执行,或者如果分析完成,输出 Final Answer 汇总所有发现。", + "content": "如果分析已经完成了,请立即输出 Final Answer 汇总所有发现。如果分析未完成,请继续分析:你输出了 Thought 但没有输出 Action。请**立即**选择一个工具执行。", }) # 🔥 如果循环结束但没有发现,强制 LLM 总结 diff --git a/frontend/src/pages/AgentAudit/components/LogEntry.tsx b/frontend/src/pages/AgentAudit/components/LogEntry.tsx index 0b0dad0..18e42af 100644 --- a/frontend/src/pages/AgentAudit/components/LogEntry.tsx +++ b/frontend/src/pages/AgentAudit/components/LogEntry.tsx @@ -244,9 +244,74 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L )} {/* Content */} -
-                  {item.content}
-                
+ {(() => { + // Try to parse JSON content + let parsedContent: any = null; + let isJson = false; + try { + if (item.content && (item.content.trim().startsWith('{') || item.content.trim().startsWith('['))) { + // Remove any "Output:" prefix if present for parsing + const cleanContent = item.content.replace(/^Output:\s*/, '').trim(); + parsedContent = JSON.parse(cleanContent); + isJson = true; + } + } catch (e) { + // Not JSON + } + + // 1. Findings View (if it looks like a findings list or object) + if (isJson && ( + (Array.isArray(parsedContent) && parsedContent.length > 0 && parsedContent[0].title && parsedContent[0].severity) || + (parsedContent.findings && Array.isArray(parsedContent.findings)) + )) { + const findingsList = Array.isArray(parsedContent) ? parsedContent : parsedContent.findings; + + return ( +
+
+ Findings Summary ({findingsList.length}) +
+ {findingsList.map((finding: any, idx: number) => ( +
+
+ {finding.title || 'Unknown Vulnerability'} + + {finding.severity || 'unknown'} + +
+
+ {finding.file_path}:{finding.line_start || '?'} +
+ {finding.description && ( +
+ {finding.description} +
+ )} +
+ ))} +
+ Raw Details Hidden (Toggle not impl yet) +
+
+ ); + } + + // 2. Generic JSON View (Pretty Print) + if (isJson) { + return ( +
+                        {JSON.stringify(parsedContent, null, 2)}
+                      
+ ); + } + + // 3. Fallback: Raw Text + return ( +
+                      {item.content}
+                    
+ ); + })()} )} diff --git a/frontend/src/pages/AgentAudit/utils.ts b/frontend/src/pages/AgentAudit/utils.ts index 01e2f20..5ce0f24 100644 --- a/frontend/src/pages/AgentAudit/utils.ts +++ b/frontend/src/pages/AgentAudit/utils.ts @@ -128,7 +128,7 @@ export function cleanThinkingContent(content: string): string { /** * Truncate output string */ -export function truncateOutput(output: string, maxLength: number = 1000): string { +export function truncateOutput(output: string, maxLength: number = 50000): string { if (output.length <= maxLength) return output; return output.slice(0, maxLength) + '\n... (truncated)'; }