
     4Wj`                        d Z ddlmZ ddlZddlZddlZej                  j                  dd      Z	ej                  j                  dej                  j                  dd            Z
d	Zdd
ZddZy)u4  Auto-supersession — temporal versioning of memory.

When a new durable fact UPDATES one already stored (a client's ticket size
changed, a plan moved, a status flipped), we don't want two contradictory facts
sitting side by side — the latest should win while the old is kept as history
(queryable, never deleted). This asks the LOCAL model whether the new fact
replaces one of the few most-similar existing facts and returns that fact's id
(else None); the engine then calls /supersede instead of /remember. Free (local
model). MEM_SUPERSEDE=0 disables.

FALLBACK PATH ONLY: the memory service now owns dedup/supersede inside its own
server-side write pipeline, so this client-side round-trip runs only when
MEM_SERVER_PIPELINE=0 is set (see voice/memory_control.py fire_save). Kept
importable for that escape hatch.
    )annotationsN
OLLAMA_URLzhttp://127.0.0.1:11434MEM_EXTRACT_MODELLOCAL_MODELzqwen3:4b-instructui  A new fact about Ahmed just arrived. Decide if it is an UPDATE that REPLACES one of the existing facts below — i.e. it describes the SAME thing (same person/company and same attribute) but with a CHANGED or newer value or status. It is NOT a replacement if it is merely related, additional, or about something else — only say it replaces one when the new value genuinely supersedes the old.

New fact: "{new}"

Existing facts (id: text):
{cands}

If the new fact replaces exactly ONE existing fact, output ONLY that fact's id.
If it replaces none, output exactly: NONE
Output only the id or NONE — nothing else.c                   	 ddl m} |j                         r=|j                  | t        j
                  j                  d|j                        dd      S 	 	 t        j                  t        dd| d	gd
did      j                         }t        j                  j                  t          d|ddi      }t        j                  j#                  |d      5 }t        j$                  |j'                               }ddd       j                  d      xs i j                  d      xs dj)                         S # t        $ r Y w xY w# 1 sw Y   NxY w# t        $ r Y yw xY w)zJudge with DeepSeek V4 Flash (smart + cheap) if a key is set, else the
    local model. Judging supersession needs more nuance than qwen3:4b has.r   )deepseekMEM_JUDGE_MODEL      )model
max_tokenstimeoutFuser)rolecontenttemperature)r   streammessagesoptionsz	/api/chatzContent-Typezapplication/json)dataheaders)r   Nmessager    )voicer   	availablechatosenvirongetFLASH	ExceptionjsondumpsMODELencodeurllibrequestRequestOLLAMAurlopenloadsreadstrip)promptr   bodyreqros         D/Users/ahmed/devFolder/Ultron/claude-voice/voice/memory_supersede.py_askr4   *   sJ   "==bjjnn->O ! , ,  zze"(V<=%q)
  68	 	
 nn$$xy%9.<>P-Q % S^^##C#4

1668$A 5y!'R,,Y7=2DDFF   54  s=   AD7 A>E $E9=E 7	EEEE 	EEc                X   t         j                  j                  dd      dk(  ry| xs dj                         } |xs g D cg c](  }|j                  d      s|j                  d      s'|* c}dd }t	        |       d	k  s|sy|D ch c]  }|d   	 }}d
j                  d |D              }t        j                  | |      }t        |      }|sy|j                  dd      j                  dd      j                  dd      j                         D ]
  }||v s|c S  yc c}w c c}w )zAReturn the id of the existing fact the new one replaces, or None.MEM_SUPERSEDE10Nr   idfact      
c              3  6   K   | ]  }|d     d|d      yw)r9   z: r:   N ).0cs     r3   	<genexpr>z"find_superseded.<locals>.<genexpr>M   s$     A5a1T7)2ai[15s   )newcands" ':)r   r   r   r-   lenjoin_PROMPTformatr4   replacesplit)	new_text
candidatesrA   rD   idslistingr.   anstoks	            r3   find_supersededrU   D   s   	zz~~os+s2B%%'H#)r)L)1aeeDkaeeFmQ)LRaPE
8}q!
"Eq1T7EC
"iiA5AAG^^^8F
v,C{{3$,,S#6>>sCHNNP#:J Q  M #s   D"D"*D"	D')r.   strreturnrV   )rO   rV   rP   z
list[dict]rW   z
str | None)__doc__
__future__r   r"   r   urllib.requestr&   r   r   r)   r$   rK   r4   rU   r?       r3   <module>r\      sg    #  	 	&>	?


*zz~~m5HI	K0 4r[   