from __future__ import annotations import re from typing import List, Optional from models import ParsedContext def extract_section(text: str, start_label: str, end_labels: List[str]) -> str: start_idx = text.find(start_label) if start_idx == -1: return "" start_idx += len(start_label) remaining = text[start_idx:] end_positions = [] for label in end_labels: idx = remaining.find(label) if idx != -1: end_positions.append(idx) if end_positions: end_idx = min(end_positions) return remaining[:end_idx].strip() return remaining.strip() def parse_hidden_context(message: str) -> ParsedContext: raw = message or "" visible_user_text = "" question_text = "" options_text = "" recent_conversation = "" if "USER_MESSAGE:" in raw: visible_user_text = extract_section(raw, "USER_MESSAGE:", []) elif "Latest player message:" in raw: visible_user_text = extract_section(raw, "Latest player message:", []) elif "Player message:" in raw: visible_user_text = extract_section(raw, "Player message:", []) else: visible_user_text = raw.strip() if "Question:" in raw: question_text = extract_section( raw, "Question:", [ "\nOptions:", "\nPlayer balance:", "\nLast outcome:", "\nRecent conversation:", "\nLatest player message:", "\nPlayer message:", "\nUSER_MESSAGE:", ], ) if "Options:" in raw: options_text = extract_section( raw, "Options:", [ "\nPlayer balance:", "\nLast outcome:", "\nRecent conversation:", "\nLatest player message:", "\nPlayer message:", "\nUSER_MESSAGE:", ], ) if "Recent conversation:" in raw: recent_conversation = extract_section( raw, "Recent conversation:", [ "\nLatest player message:", "\nPlayer message:", "\nUSER_MESSAGE:", ], ) combined_parts = [] if question_text: combined_parts.append(question_text.strip()) if options_text: combined_parts.append(options_text.strip()) combined_question_block = "\n".join([p for p in combined_parts if p]).strip() if not combined_question_block: combined_question_block = raw.strip() return ParsedContext( raw_message=raw, visible_user_text=visible_user_text.strip(), full_context_text=raw.strip(), question_text=question_text.strip(), options_text=options_text.strip(), combined_question_block=combined_question_block.strip(), recent_conversation=recent_conversation.strip(), ) def detect_help_mode(user_text: str, supplied: Optional[str]) -> str: lower = (user_text or "").lower().strip() if supplied in {"hint", "walkthrough", "answer"}: if "hint" in lower: return "hint" if ( "walkthrough" in lower or "step by step" in lower or "work through" in lower or "explain step by step" in lower ): return "walkthrough" if "why" in lower or "explain" in lower: return "walkthrough" return supplied if lower in {"hint", "just a hint", "hint please", "small hint"}: return "hint" if "hint" in lower: return "hint" if ( "walkthrough" in lower or "step by step" in lower or "work through" in lower or "explain step by step" in lower ): return "walkthrough" if "why" in lower or "explain" in lower: return "walkthrough" return "answer" def user_is_referring_to_existing_question(user_text: str, question_text: str) -> bool: lower = (user_text or "").lower().strip() if not question_text: return False short_refs = { "help", "hint", "why", "why?", "explain", "explain it", "explain this", "answer", "what's the answer", "what is the answer", "is it a", "is it b", "is it c", "is it d", "is it e", "which one", "which option", "what do i do first", "what do i do", "how do i start", "are you sure", "can you help", "help me", "i don't get it", "i dont get it", "why is it c", "why is it b", "why is it a", "why is it d", "why is it e", "what is the question asking me to do", "what is this asking", "what do you need", } if lower in short_refs: return True if any( phrase in lower for phrase in [ "is it ", "why", "hint", "explain", "answer", "help", "first step", "what is the question asking", "what is this asking", "what do you need", ] ): return True return False def mentions_choice_letter(user_text: str) -> Optional[str]: lower = (user_text or "").lower().strip() m = re.search(r"\b(?:is it|answer is|it's|its|option|choice)\s*([a-e])\b", lower) if m: return m.group(1).upper() m = re.search(r"\bwhy is it\s*([a-e])\b", lower) if m: return m.group(1).upper() if lower in {"a", "b", "c", "d", "e"}: return lower.upper() return None