"""synthesizer_node — at the end of the tool loop, take the last AIMessage.content as final_answer.""" from __future__ import annotations from langchain_core.messages import AIMessage from graph.states.chat_state import ChatState async def synthesizer_node(state: ChatState) -> dict: """Take the last AIMessage.content from messages as final_answer.""" messages = state.get("messages") or [] last_ai_content = "" for m in reversed(messages): if isinstance(m, AIMessage): content = m.content if isinstance(content, str) and content.strip(): last_ai_content = content break elif isinstance(content, list): # Anthropic-style content blocks text_parts = [ part.get("text", "") for part in content if isinstance(part, dict) and part.get("type") == "text" ] if any(text_parts): last_ai_content = "\n".join(t for t in text_parts if t) break return { "final_answer": last_ai_content or "(empty answer)", "trace": [f"synthesizer: {len(last_ai_content)} characters"], }