"""Parsing the memory extractor's answer, and deciding which scope a fact lands in. Blueprint 6.9 and master prompt 4.5. The asymmetry is the whole design: * A fact extracted from a **Normal-mode** conversation is always ``shared``. Nothing said in a room where others can read the screen is private by construction. * A fact from **GF mode** is whatever the extractor says — and when the answer is malformed, missing a scope, or anything other than a clean ``shared``, it defaults to ``private``. Leaking a private fact into Normal mode is far worse than failing to surface a harmless one, so every uncertainty resolves toward ``private``. """ from dataclasses import dataclass from ..persona import prova from ..persona.types import Mode, Scope #: Longest a stored fact may be. The extractor is told "one short sentence"; anything much #: longer is the model narrating the conversation back, which is not a fact. MAX_FACT_CHARS = 280 @dataclass(frozen=True) class ExtractedFact: scope: Scope content: str def parse_extraction(raw: str, mode: Mode) -> ExtractedFact | None: """``None`` means there is nothing worth remembering.""" text = raw.strip().strip('"').strip() if not text or text.upper().rstrip(".") == prova.MEMORY_EXTRACTION_NONE: return None # Only the first line counts. A chatty model that adds "Hope that helps!" underneath has not # changed the fact. line = text.splitlines()[0].strip() if line.upper().rstrip(".") == prova.MEMORY_EXTRACTION_NONE: return None scope_text, separator, fact = line.partition("|") if not separator: # No scope at all. The whole line is the fact and the scope is unknown. fact, scope = line, Scope.PRIVATE else: scope = _scope_from(scope_text) fact = fact.strip().strip('"').strip() if not fact or len(fact) > MAX_FACT_CHARS: return None if fact.upper().rstrip(".") == prova.MEMORY_EXTRACTION_NONE: return None # Normal-mode talk is never private, whatever the extractor thought. if mode is Mode.NORMAL: scope = Scope.SHARED return ExtractedFact(scope=scope, content=fact) def _scope_from(text: str) -> Scope: """Only an exact ``shared`` is shared. Everything else — including typos — is private.""" return Scope.SHARED if text.strip().lower() == "shared" else Scope.PRIVATE def forced_scope(requested: str | None, mode: Mode) -> Scope: """The scope for a fact he asked her to remember via the ``remember`` tool. Blueprint 8.1: "In Normal mode, scope is forced to shared." """ if mode is Mode.NORMAL: return Scope.SHARED if requested and requested.strip().lower() == "shared": return Scope.SHARED return Scope.PRIVATE if requested else Scope.SHARED