
    Ui^&                        d Z ddlmZ ddlZddlmZ ddlmZmZm	Z	m
Z
mZ ddlmZmZmZ ddlmZ  ej$                  d	      Z G d
 d      Zy)a  RLM Neo-Cortex -- Surprise Integration.

Wraps core.surprise_memory.MemorySystem (v2.0.0, 585 lines) into the
Gateway's tier-routing pipeline. Does NOT rebuild surprise scoring --
bridges it with tier-awareness, write gating, batch scoring, and
statistics reporting.

Public API:
    score_content(content, source, domain) -> (float, MemoryTier)
    score_content_for_tier(content, source, domain, tier) -> (float, MemoryTier)
    register_prediction(domain, expected, confidence) -> str
    resolve_prediction(prediction_id, actual_outcome) -> (float, MemoryTier)
    score_batch(items) -> list[(float, MemoryTier)]
    get_stats() -> dict
    get_score_distribution() -> dict
    )annotationsN)defaultdict)AnyDictListOptionalTuple   )CustomerTier
MemoryTierSurpriseIntegrationProtocol)get_thresholdszcore.rlm.surprisec                      e Zd ZU dZddddZded<   ddd	Z	 	 	 	 	 	 	 	 dd
Z	 	 	 	 	 	 	 	 	 	 ddZ	 d	 	 	 	 	 	 	 ddZ		 	 	 	 	 	 ddZ
	 	 	 	 ddZddZddZe	 	 	 	 	 	 dd       Zy)SurpriseIntegrationaw  Bridges existing surprise engine to Gateway tier routing.

    Wraps :class:`core.surprise_memory.MemorySystem` and adds:
      - Tier-aware threshold routing (different tiers have different sensitivity)
      - Write gating (below discard threshold = memory not stored)
      - Batch scoring for nightly consolidation
      - Statistics and score distribution reporting
    g333333?g      ?g?)discardworkingepisodicDict[str, float]TIER_THRESHOLDSNc                b    ddl m}  ||      | _        g | _        t        j                  d       y)zInitialize wrapper around existing MemorySystem.

        Args:
            persistence_path: Optional path for surprise history persistence.
                Forwarded to the underlying MemorySystem constructor.
        r   )MemorySystemz<SurpriseIntegration initialized wrapping MemorySystem v2.0.0N)core.surprise_memoryr   _engine_score_historyloggerinfo)selfpersistence_pathr   s      */mnt/e/genesis-system/core/rlm/surprise.py__init__zSurpriseIntegration.__init__0   s)     	6#$4579RS    c                    | j                   j                  |||      }|d   d   }| j                  || j                        }| j                  j                  ||f       ||fS )a  Score content and return (score, tier) tuple.

        Uses default thresholds (not tier-aware). For tier-specific
        routing, use :meth:`score_content_for_tier`.

        Args:
            content: The text content to evaluate for surprise.
            source: Origin of the content (e.g. 'voice_agent', 'system').
            domain: Domain category (e.g. 'sales', 'operations').

        Returns:
            Tuple of (composite_score, MemoryTier).
        scorecomposite_score)r   evaluate_classify_tierr   r   append)r   contentsourcedomainresultr#   tiers          r   score_contentz!SurpriseIntegration.score_contentA   se      &&w?w 12""5$*>*>?""E6?3d{r!   c                    | j                   j                  |||      }|d   d   }t        |j                        }| j	                  ||      }| j
                  j                  ||f       ||fS )aE  Score content with tier-adjusted thresholds.

        The raw surprise score is identical regardless of tier -- only
        the classification thresholds change. Enterprise/Queen tiers
        have lower discard thresholds (capture more), while Starter
        has a higher discard threshold (more selective).

        Args:
            content: The text content to evaluate.
            source: Origin of the content.
            domain: Domain category.
            tier: Customer subscription tier.

        Returns:
            Tuple of (composite_score, MemoryTier).
        r#   r$   )r   r%   r   valuer&   r   r'   )	r   r(   r)   r*   r,   r+   r#   
thresholdsmemory_tiers	            r   score_content_for_tierz*SurpriseIntegration.score_content_for_tier[   sn    . &&w?w 12#DJJ/
))%<""E6?3k!!r!   c                <    | j                   j                  |||      S )a  Register a prediction for later surprise resolution.

        Forwards to the underlying engine's make_prediction().

        Args:
            domain: Domain context for the prediction.
            expected: The expected outcome string.
            confidence: Confidence level (0-1) in the prediction.

        Returns:
            prediction_id string for later resolution.
        )r   make_prediction)r   r*   expected
confidences       r   register_predictionz'SurpriseIntegration.register_prediction}   s     ||++FHjIIr!   c                    | j                   j                  ||      \  }}|j                  }| j                  || j                        }| j
                  j                  |df       ||fS )a  Resolve a prediction and return surprise-based tier routing.

        Args:
            prediction_id: ID returned by register_prediction().
            actual_outcome: What actually happened.

        Returns:
            Tuple of (error_score, MemoryTier).
        
prediction)r   resolve_predictiontotalr&   r   r   r'   )r   prediction_idactual_outcomeerror_scoresurprise_scorer#   r,   s          r   r:   z&SurpriseIntegration.resolve_prediction   sj     '+ll&E&E>'
#^ $$""5$*>*>?""E<#89d{r!   c                2   |sg S h d}g }t        |      D ]~  \  }}|t        |j                               z
  }|r)t        d| ddj	                  t        |                   | j                  |d   |d   |d         \  }}|j                  ||f        |S )aq  Score multiple items efficiently.

        Each item dict must contain keys: content, source, domain.

        Args:
            items: List of dicts, each with 'content', 'source', 'domain'.

        Returns:
            List of (score, MemoryTier) tuples in same order as input.

        Raises:
            ValueError: If any item is missing a required key.
        >   r*   r)   r(   zItem at index z missing required key(s): z, r(   r)   r*   )	enumeratesetkeys
ValueErrorjoinsortedr-   r'   )	r   itemsrequired_keysresultsidxitemmissingr#   r,   s	            r   score_batchzSurpriseIntegration.score_batch   s      I724"5) 
	*IC#c$))+&66G $SE)Cyy124  ,,YhhKE4 NNE4=)
	* r!   c                6    | j                   j                         S )zReturn surprise engine statistics including domain baselines.

        Returns:
            Dict with keys: total_events, avg_surprise, domains,
            level_distribution, active_predictions.
        )r   	get_stats)r   s    r   rO   zSurpriseIntegration.get_stats   s     ||%%''r!   c                    t        t              }t        D ]  }d||j                  <    | j                  D ]8  \  }}| j                  || j                        }||j                  xx   dz  cc<   : t        |      S )a  Return distribution of scores across MemoryTier values.

        Uses the internal score history to compute how many scores
        fell into each tier bucket using default thresholds.

        Returns:
            Dict mapping MemoryTier value strings to counts.
        r   r
   )r   intr   r/   r   r&   r   dict)r   distributiontier_valr#   _r,   s         r   get_score_distributionz*SurpriseIntegration.get_score_distribution   s     (33'7" 	-H+,L(	- ++ 	*HE1&&ud.B.BCD$)$	* L!!r!   c                    | |d   k  rt         j                  S | |d   k  rt         j                  S | |d   k  rt         j                  S t         j                  S )a  Classify a surprise score into a MemoryTier.

        Boundary rules:
            score < discard threshold       -> DISCARD
            discard <= score < working       -> WORKING
            working <= score < episodic      -> EPISODIC
            score >= episodic                -> SEMANTIC

        Args:
            score: The composite surprise score (0-1).
            thresholds: Dict with keys 'discard', 'working', 'episodic'.

        Returns:
            The appropriate MemoryTier.
        r   r   r   )r   DISCARDWORKINGEPISODICSEMANTIC)r#   r0   s     r   r&   z"SurpriseIntegration._classify_tier   s[    & :i((%%%Z	**%%%Z
++&&&&&&r!   )N)r   zOptional[str]returnNone)r(   strr)   r^   r*   r^   r\   Tuple[float, MemoryTier])
r(   r^   r)   r^   r*   r^   r,   r   r\   r_   )gffffff?)r*   r^   r5   r^   r6   floatr\   r^   )r<   r^   r=   r^   r\   r_   )rG   zList[Dict[str, Any]]r\   zList[Tuple[float, MemoryTier]])r\   zDict[str, Any])r\   zDict[str, int])r#   r`   r0   r   r\   r   )__name__
__module____qualname____doc__r   __annotations__r    r-   r2   r7   r:   rM   rO   rV   staticmethodr&    r!   r   r   r      s    )O% T"$'14	!4"" " 	"
 " 
""F ?BJJ%(J6;J	J" 25	!0")"	'"P(". ''"2'	' 'r!   r   )rd   
__future__r   loggingcollectionsr   typingr   r   r   r   r	   	contractsr   r   r   surprise_configr   	getLoggerr   r   rg   r!   r   <module>ro      sC     #  # 3 3 L L +			.	/k' k'r!   