refactor: address code review - extract helpers for content extraction and message parsing

Co-authored-by: aguzererler <6199053+aguzererler@users.noreply.github.com>
Agent-Logs-Url: https://github.com/aguzererler/TradingAgents/sessions/5c511c4e-5172-4eda-b6de-aefa1859e8ac
This commit is contained in:
copilot-swe-agent[bot] 2026-03-23 00:53:25 +00:00
parent e9be24600f
commit 7726483034
1 changed files with 31 additions and 12 deletions

View File

@ -111,6 +111,12 @@ class LangGraphEngine:
# Last resort: the event name itself # Last resort: the event name itself
return event.get("name", "unknown") return event.get("name", "unknown")
@staticmethod
def _extract_content(obj: object) -> str:
"""Safely extract text content from a LangChain message or plain object."""
content = getattr(obj, "content", None)
return str(content) if content is not None else str(obj)
@staticmethod @staticmethod
def _truncate(text: str, max_len: int = _MAX_CONTENT_LEN) -> str: def _truncate(text: str, max_len: int = _MAX_CONTENT_LEN) -> str:
if len(text) <= max_len: if len(text) <= max_len:
@ -129,6 +135,24 @@ class LangGraphEngine:
"metrics": {}, "metrics": {},
} }
@staticmethod
def _first_message_content(messages: Any) -> str:
"""Extract content from the first message in a LangGraph messages payload.
``messages`` may be a flat list of message objects or a list-of-lists.
Returns an empty string when extraction fails.
"""
if not isinstance(messages, list) or not messages:
return ""
first_item = messages[0]
# Handle list-of-lists (nested batches)
if isinstance(first_item, list):
if not first_item:
return ""
first_item = first_item[0]
content = getattr(first_item, "content", None)
return str(content) if content is not None else str(first_item)
def _map_langgraph_event( def _map_langgraph_event(
self, run_id: str, event: Dict[str, Any] self, run_id: str, event: Dict[str, Any]
) -> Dict[str, Any] | None: ) -> Dict[str, Any] | None:
@ -147,13 +171,9 @@ class LangGraphEngine:
prompt_snippet = "" prompt_snippet = ""
messages = (event.get("data") or {}).get("messages") messages = (event.get("data") or {}).get("messages")
if messages: if messages:
# messages may be a list of lists or a list of message objects raw = self._first_message_content(messages)
flat = messages if not isinstance(messages, list) else messages if raw:
if isinstance(flat, list) and flat: prompt_snippet = self._truncate(raw)
first = flat[0] if not isinstance(flat[0], list) else (flat[0][0] if flat[0] else None)
if first is not None:
content = getattr(first, "content", str(first))
prompt_snippet = self._truncate(str(content))
model = "unknown" model = "unknown"
inv_params = (event.get("data") or {}).get("invocation_params") or {} inv_params = (event.get("data") or {}).get("invocation_params") or {}
@ -199,8 +219,7 @@ class LangGraphEngine:
tool_output = "" tool_output = ""
out = (event.get("data") or {}).get("output") out = (event.get("data") or {}).get("output")
if out is not None: if out is not None:
content = getattr(out, "content", str(out)) tool_output = self._truncate(self._extract_content(out))
tool_output = self._truncate(str(content))
logger.info("Tool end tool=%s node=%s run=%s", name, node_name, run_id) logger.info("Tool end tool=%s node=%s run=%s", name, node_name, run_id)
@ -227,9 +246,9 @@ class LangGraphEngine:
usage = output.usage_metadata usage = output.usage_metadata
if hasattr(output, "response_metadata") and output.response_metadata: if hasattr(output, "response_metadata") and output.response_metadata:
model = output.response_metadata.get("model_name", model) model = output.response_metadata.get("model_name", model)
content = getattr(output, "content", "") raw = self._extract_content(output)
if content: if raw:
response_snippet = self._truncate(str(content)) response_snippet = self._truncate(raw)
latency_ms = 0 latency_ms = 0
start_t = starts.pop(node_name, None) start_t = starts.pop(node_name, None)