"""In-process conversation history for AgentCore / LangGraph orchestration.""" from __future__ import annotations import threading from typing import Any from langchain_core.messages import AIMessage, BaseMessage, HumanMessage _lock = threading.Lock() _sessions: dict[str, list[BaseMessage]] = {} def _session_key(session_hash: str | None) -> str: key = (session_hash or "").strip() return key or "default" def get_messages(session_hash: str | None) -> list[BaseMessage]: """Return a copy of stored messages for *session_hash*.""" key = _session_key(session_hash) with _lock: return list(_sessions.get(key, [])) def clear_session(session_hash: str | None) -> None: """Drop conversation history for *session_hash*.""" key = _session_key(session_hash) with _lock: _sessions.pop(key, None) def append_turn( session_hash: str | None, *, user_text: str, assistant_text: str = "", ) -> None: """Append one user turn and optional assistant reply.""" key = _session_key(session_hash) with _lock: history = _sessions.setdefault(key, []) history.append(HumanMessage(content=user_text)) if assistant_text.strip(): history.append(AIMessage(content=assistant_text.strip())) def stringify_message_content(content: Any) -> str: """Normalize LangChain message content to plain text.""" if isinstance(content, str): return content if isinstance(content, list): parts: list[str] = [] for block in content: if isinstance(block, str): parts.append(block) elif isinstance(block, dict) and block.get("type") == "text": parts.append(str(block.get("text") or "")) return "".join(parts) return str(content or "")