"""Deterministic preferred-name/form-of-address extraction. "I am X" is deliberately excluded: it matches too many non-name sentences ("I am confused", "I am working on..."). Patterns use a lookahead rather than an end-of-string anchor so a name followed by more sentence content ("My name is Anshuman, and I'm studying robotics") still matches. See docs/commit-memory-adaptation-architecture.md. """ from __future__ import annotations import re _NAME_SIGNAL_PATTERNS = ( re.compile( r"\bmy name is\s+([A-Za-z][A-Za-z .'-]{0,48}?)(?=\s+(?:and|but)\b|[,.;!?\n]|$)", re.IGNORECASE, ), re.compile( r"\b(?:please\s+)?call me\s+([A-Za-z][A-Za-z .'-]{0,48}?)(?=\s+(?:and|but)\b|[,.;!?\n]|$)", re.IGNORECASE, ), re.compile( r"\byou can call me\s+([A-Za-z][A-Za-z .'-]{0,48}?)(?=\s+(?:and|but)\b|[,.;!?\n]|$)", re.IGNORECASE, ), re.compile( r"\bi go by\s+([A-Za-z][A-Za-z .'-]{0,48}?)(?=\s+(?:and|but)\b|[,.;!?\n]|$)", re.IGNORECASE, ), ) def extract_preferred_name(text: str) -> str | None: for pattern in _NAME_SIGNAL_PATTERNS: match = pattern.search(text or "") if not match: continue name = re.sub(r"\s+", " ", match.group(1)).strip(" .'-") if 1 < len(name) <= 80: return name return None