"""Notebook-oriented presentation helpers for analysis results.""" from __future__ import annotations import html from typing import Iterable from .agent_runner import AgentStepTrace, AnalysisRunResult def _tool_label(tool_name: str | None) -> str: if tool_name == "PythonInterpreterTool": return "本地 Python 分析" if tool_name == "TavilySearchTool": return "联网背景检索" if tool_name: return tool_name return "报告收敛" def _status_label(status: str) -> str: mapping = { "success": "成功", "partial": "部分完成", "error": "失败", "unknown": "未知", } return mapping.get(status, status) def _escape(value: object) -> str: return html.escape(str(value)) def _trace_short_observation(trace: AgentStepTrace) -> str: if trace.observation_preview: return trace.observation_preview if trace.observation: return " ".join(trace.observation.split())[:220] return "" def _iter_failed_traces(step_traces: Iterable[AgentStepTrace]) -> list[AgentStepTrace]: failed = [] for trace in step_traces: observation = trace.observation or "" if trace.tool_status == "error" or "Traceback" in observation: failed.append(trace) return failed def render_trace_table(result: AnalysisRunResult): """Render the agent reasoning trace as notebook-friendly HTML.""" from IPython.display import HTML rows = [] for trace in result.step_traces: if trace.action == "call_tool": stage = f"{_tool_label(trace.tool_name)} ({trace.tool_name})" else: stage = "最终报告" rows.append( """
| Step | Stage / Tool | Decision | Status | Short Observation | Notes |
|---|
本次运行无工具级异常。
") details_blocks = [] for trace in failed_traces: title = f"Step {trace.step_index} Traceback" body = _escape(trace.observation or trace.parse_error or "No diagnostic text available.") details_blocks.append( f"""{body}