|  | from typing import Tuple | 
					
						
						|  |  | 
					
						
						|  | import logging | 
					
						
						|  |  | 
					
						
						|  | from langchain_core.messages import AIMessage, HumanMessage | 
					
						
						|  |  | 
					
						
						|  | def add_details(response: str, reasoning: str, svg_argmap: str) -> str: | 
					
						
						|  | """Add reasoning details to the response message shown in chat.""" | 
					
						
						|  | response_with_details = ( | 
					
						
						|  | f"<p>{response}</p>" | 
					
						
						|  | '<details id="reasoning">' | 
					
						
						|  | "<summary><i>Internal reasoning trace</i></summary>" | 
					
						
						|  | f"<code>{reasoning}</code></details>" | 
					
						
						|  | '<details id="svg_argmap">' | 
					
						
						|  | "<summary><i>Argument map</i></summary>" | 
					
						
						|  | f"\n<div>\n{svg_argmap}\n</div>\n</details>" | 
					
						
						|  | ) | 
					
						
						|  | return response_with_details | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | def get_details(response_with_details: str) -> Tuple[str, dict[str, str]]: | 
					
						
						|  | """Extract response and details from response_with_details shown in chat.""" | 
					
						
						|  | if "<details id=" not in response_with_details: | 
					
						
						|  | return response_with_details, {} | 
					
						
						|  | details_dict = {} | 
					
						
						|  | response, *details_raw = response_with_details.split('<details id="') | 
					
						
						|  | for details in details_raw: | 
					
						
						|  | details_id, details_content = details.split('"', maxsplit=1) | 
					
						
						|  | details_content = details_content.strip() | 
					
						
						|  | if details_content.endswith("</code></details>"): | 
					
						
						|  | details_content = details_content.split("<code>")[1].strip() | 
					
						
						|  | details_content = details_content[:-len("</code></details>")].strip() | 
					
						
						|  | elif details_content.endswith("</div></details>"): | 
					
						
						|  | details_content = details_content.split("<div>")[1].strip() | 
					
						
						|  | details_content = details_content[:-len("</div></details>")].strip() | 
					
						
						|  | else: | 
					
						
						|  | logging.warning(f"Unrecognized details content: {details_content}") | 
					
						
						|  | details_content = "UNRECOGNIZED DETAILS CONTENT" | 
					
						
						|  | details_dict[details_id] = details_content | 
					
						
						|  | return response, details_dict | 
					
						
						|  |  | 
					
						
						|  |  | 
					
						
						|  | def history_to_langchain_format(history: list[tuple[str, str]]) -> list: | 
					
						
						|  | history_langchain_format = [] | 
					
						
						|  | for human, ai in history: | 
					
						
						|  | history_langchain_format.append(HumanMessage(content=human)) | 
					
						
						|  | if ai is None: | 
					
						
						|  | continue | 
					
						
						|  | response, details = get_details(ai) | 
					
						
						|  | logging.debug(f"Details: {details}") | 
					
						
						|  | content = response | 
					
						
						|  | if "reasoning" in details: | 
					
						
						|  | content += ( | 
					
						
						|  | "\n\n" | 
					
						
						|  | "#+BEGIN_INTERNAL_TRACE // Internal reasoning trace (hidden from user)\n" | 
					
						
						|  | f"{details.get('reasoning', '')}\n" | 
					
						
						|  | "#+END_INTERNAL_TRACE" | 
					
						
						|  | ) | 
					
						
						|  | history_langchain_format.append(AIMessage(content=content)) | 
					
						
						|  | return history_langchain_format | 
					
						
						|  |  |