diff --git a/webapp/main.py b/webapp/main.py index 438f0642..0958e647 100644 --- a/webapp/main.py +++ b/webapp/main.py @@ -266,18 +266,18 @@ def create_agent_node(agent_id: str, agent_name: str): "content": f"Agent: {agent_name} - Awaiting execution", "children": [ { - "id": f"{agent_id}_report", - "name": "📄 Report", - "status": "pending", - "content": "Report not yet generated", + "id": f"{agent_id}_messages", + "name": "� Messages", + "status": "pending", + "content": "No messages yet", "children": [], "timestamp": time.time() }, { - "id": f"{agent_id}_messages", - "name": "💬 Messages", - "status": "pending", - "content": "No messages yet", + "id": f"{agent_id}_report", + "name": "� Report", + "status": "pending", + "content": "Report not yet generated", "children": [], "timestamp": time.time() } @@ -355,12 +355,54 @@ def format_report_content(report_name: str, report_data: any) -> str: def extract_agent_messages(state: dict, agent_id: str) -> str: """Extract relevant messages for an agent from the state.""" - # This is a simplified version - could be enhanced to extract actual messages - messages = state.get("messages", []) - if messages: - return f"💬 Agent Messages\n\n{len(messages)} messages exchanged during execution" - else: - return "💬 Agent Messages\n\nExecution completed without specific message logs" + # Expecting state['messages'] to be a list of dicts with optional keys like + # 'role', 'content', 'timestamp'. We'll display each in an expandable box. + messages = state.get("messages", []) or [] + if not messages: + return "💬 Agent Messages\n\nNo messages recorded for this agent." + + # Filter messages for this agent if agent_id field present + filtered = [] + for m in messages: + if isinstance(m, dict): + msg_agent = m.get("agent_id") or m.get("agent") + if msg_agent and msg_agent != agent_id: + continue + filtered.append(m) + else: + # Try common attributes used by message objects (e.g., langchain HumanMessage / AIMessage) + msg_agent = getattr(m, "agent_id", None) or getattr(m, "agent", None) + if msg_agent and msg_agent != agent_id: + continue + filtered.append(m) + if not filtered: + filtered = messages # fallback to all if no agent-specific match + + parts = ["💬 Agent Messages", "", f"Total messages: {len(filtered)}", ""] + for idx, m in enumerate(filtered, start=1): + if isinstance(m, dict): + role = m.get("role") or m.get("type") or "message" + ts = m.get("timestamp") + content = m.get("content") or m.get("text") or "(no content)" + else: + # Object-based message + role = getattr(m, "role", None) or getattr(m, "type", None) or m.__class__.__name__ + ts = getattr(m, "timestamp", None) + # LangChain messages often have a .content attribute + content = getattr(m, "content", None) or getattr(m, "text", None) or str(m) + # Escape triple backticks to avoid markdown parser confusion + if isinstance(content, str): + content = content.replace('```', '\u0060\u0060\u0060') + header = f"{idx}. {role.title()}" + (f" – {ts}" if ts else "") + # Use HTML
so user can expand long messages + parts.append( + f"
") + parts.append(f" {header}") + # Wrap content in pre for formatting + parts.append("
" + str(content) + "
") + parts.append("
") + + return "\n".join(parts) def recalc_phase_statuses(execution_tree: list): """Recalculate each phase's status: pending (no started), in_progress (some running/completed but not all), completed (all done), error if any child error.""" diff --git a/webapp/static/styles.css b/webapp/static/styles.css index 3860aa51..9568a88a 100644 --- a/webapp/static/styles.css +++ b/webapp/static/styles.css @@ -419,6 +419,40 @@ body { padding: 12px; overflow-x: auto; } + +/* Expandable message boxes for Messages view */ +details.message-box { + background: var(--bg-secondary); + border: 1px solid var(--border-color); + border-radius: 6px; + margin-bottom: 10px; + padding: 6px 10px; +} + +details.message-box > summary { + cursor: pointer; + font-weight: 600; + list-style: none; +} + +details.message-box > summary::-webkit-details-marker { + display: none; +} + +details.message-box[open] { + box-shadow: 0 2px 4px rgba(0,0,0,0.25); +} + +pre.message-content { + background: var(--bg-primary); + border: 1px solid var(--border-color); + border-radius: 4px; + padding: 10px; + margin: 8px 0 4px 0; + max-height: 400px; + overflow: auto; + font-size: 0.85rem; +} .markdown-body table { width: 100%; border-collapse: collapse;