+
    „WÝjÉ¿  ã            	       óÔ  € R t ^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIHtHtH	t	 ^ RI
HtHtHtHt ^ RIHtHt ^ RIHt ^ RIHt ^ RIHt ^ R	IHtHtHtHtHtHt ^ R
IH t  ^ RI!H"t"H#t#H$t$H%t% ^ RI&H't'H(t( ^ RI)t)]PT                  ! R4      t+R t,R!t-R"t.Rt/R#t0R$t1R%t2R&t3R'R R llt4Rt5R]  R2t6R] R]7! ]4      ^,            R]7! ]4       R]6 R2	t8R]8 2t9R]8 R2t:R(R R llt; ! R R4      t<R# ))zñSession listing/rich rows, export, and import (portability) for SessionDB.

Plain mixin for ``hermes_state.SessionDB`` (no ``__init__``/state of its own).
Must never import hermes_state (cycle); shared constants live in hermes_state_common.
N)ÚCounter)ÚdatetimeÚtimezoneÚUTC)ÚAnyÚDictÚListÚOptional)ÚAUTO_LOAD_SCAFFOLD_SQL_LIKEÚSKILL_SCAFFOLD_SQL_LIKE)Úsafe_json_loads)Úcoerce_epoch)Únew_session_id)ÚCRON_PRINCIPAL_IDÚCRON_REQUEST_PREFIXÚcron_request_rangeÚcron_run_from_requestÚlegacy_cron_run_jobÚprefix_range)ÚPOLICY_PREFIX)Ú
SCHEMA_SQLÚ_shape_previewÚ_sql_preview_rawÚ_sql_session_last_active)Ú_parse_tool_callsÚ_tool_calls_countÚhermes_stateaï  INSERT INTO sessions (
                           id, source, user_id, model, model_config, system_prompt,
                           system_prompt_hash,
                           parent_session_id, started_at, ended_at, end_reason,
                           message_count, tool_call_count, input_tokens, output_tokens,
                           cache_read_tokens, cache_write_tokens, reasoning_tokens,
                           cwd, git_branch, git_repo_root,
                           billing_provider, billing_base_url, billing_mode,
                           estimated_cost_usd, actual_cost_usd, cost_status, cost_source,
                           pricing_version, title, api_call_count, archived, auto_archived, pinned, hidden
                       )
                       VALUES (
                           :id, :source, :user_id, :model, :model_config,
                           NULL, :system_prompt_hash, NULL, :started_at, :ended_at,
                           :end_reason, 0, 0, :input_tokens, :output_tokens,
                           :cache_read_tokens, :cache_write_tokens,
                           :reasoning_tokens, :cwd, :git_branch, :git_repo_root,
                           :billing_provider, :billing_base_url, :billing_mode,
                           :estimated_cost_usd, :actual_cost_usd, :cost_status,
                           :cost_source, :pricing_version, :title,
                           :api_call_count, :archived, :auto_archived, :pinned, :hidden
                       )c          
      ój   € V ^8„  d   QhR\         R\         R\         R\        \         ,          R\         /# )é   Úselect_colsÚwhereÚtailÚprompt_selectÚreturn)Ústrr	   )Úformats   "ÚLC:\Users\johnn\AppData\Local\hermes\hermes-agent\hermes_state_portability.pyÚ__annotate__r'   N   s5   € ÷ ñ œcð ¬#ð ´Sð ÌhÔWZÍmð Ôehñ ó    c                ót   € Vf   RMRpRT  T;'       g    R R\        4        R\        R4       RV RV V R2# )	zØ``list_sessions_rich``-shaped SELECT: resolved prompt (``prompt_select`` fragment;
None omits prompt columns AND the join), preview, last_active. Whitespace matches
the historical inline queries (SQL text is pinned).Ú z=LEFT JOIN system_prompts sp ON sp.hash = s.system_prompt_hashz
            SELECT ú,
                Úsz8 AS last_active
            FROM sessions s
            z
            WHERE z	
        )r   r   )r   r    r!   r"   Úprompt_joins   &&&& r&   Ú_rich_selectr.   N   sm   € ð &Ò-‘"Ð3r€KðØ�= ×!4Ð!4°"Ð 5ð 6Ü!Ó#Ð$ð %Ü)¨#Ó.Ð/ð 0àˆMð Ø�'˜$˜ð  	ðð r(   z?COALESCE(sp.prompt, s.system_prompt) AS _system_prompt_resolvedzË(SELECT CASE WHEN json_valid(r) THEN json_extract(r, '$.cron_job.id') END FROM (SELECT CASE WHEN json_valid(value) THEN json_extract(value, '$.policy.request_json') END AS r FROM state_meta WHERE key = 'z' || target_session_id))zprincipal_id = 'z\' AND request_id >= :request_lo AND request_id < :request_hi AND ((instr(substr(request_id, z ), ':') = length(:request_lo) - zE AND instr(substr(request_id, length(:request_lo) + 1), ':') = 0) OR z = :job_id)a  SELECT id FROM sessions WHERE source = 'cron' AND id >= :prefix AND id < :prefix_hi AND substr(id, length(:prefix) + 1) GLOB '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9][0-9][0-9]' UNION ALL SELECT target_session_id FROM session_admissions WHERE zo(SELECT substr(request_id, length(:request_lo) + 1) FROM session_admissions WHERE target_session_id = s.id AND z	 LIMIT 1)c                ó¬   € V ^8„  d   QhR\         \        \        \        3,          ,          R\        \        ,          R\        \        \        3,          /# )r   ÚmessagesÚ
session_idr#   )ÚlistÚdictr$   r   r	   )r%   s   "r&   r'   r'   x   s?   € ÷ %ñ %œd¤4¬¬S¨¥>Õ2ð %ÄÌÅð %ÔY]Ô^aÔcfÐ^fÕYgñ %r(   c                óü  € V  Uu. uF(  p\        VP                  R4      VR7      ;pf   K%  W#3NK*  	  pp\        R V  4       4      p\        R R V  4        4       4      p\        P
                  ! V4       UUU	U
u. uFr  w  w  rxw  ršRVP                  R4      R	V	P                  R4      R
VP                  R4      RV	P                  R4      R\        ^ \        W¨,
          R,          4      4      /NKt  	  pp	ppp
R pV'       d!   V^ ,          ^,          VR",          ^,          3MR#w  rÞRRR\        V4      RRRV'       d   RMRRR\        V4      R\        V 4      \        V4      ,
          /RVe	   V! V4      MRRVe	   V! V4      MRRV'       d#   \        ^ \        Wí,
          R,          4      4      MRRV'       d   \        R V 4       4      MRR\        V4      RVP                  R^ 4      R VR!V/# u upi u up
p	ppi )$u2  Text-free timing evidence for a session export.

Exports get attached to bug reports; a reader should not have to infer from raw
timestamps whether a slow turn was one long model gap or many small tool
intervals. Hermes persists no model/tool stopwatch samples, so message
timestamps are the durable floor (``complete`` is therefore always False).
Ids, roles, counts and durations only â€” never prompt text, arguments or results.
Corrupt timestamp cells go through ``coerce_epoch`` like every other reader: they
count as ``missing`` and never abort the export.
Ú	timestamp)r1   Nc              3   ój   "  € T F)  p\        VP                  R 4      ;'       g    R4      x € K+  	  R# 5i)ÚroleÚunknownN)r$   Úget©Ú.0Úmsgs   & r&   Ú	<genexpr>Ú"_export_timings.<locals>.<genexpr>…   s(   é € ÐPÁxÀœ#˜cŸg™g f›o×:Ð:°×;Ð;Ãxùs   ‚!3¤3c              3   óz   "  € T F1  q'       g   K  \        V\        4      '       d   \        V4      M^x € K3  	  R# 5i)é   N)Ú
isinstancer2   Úlen)r;   Útcs   & r&   r=   r>   †   s0   é € ð lÙ9d°2ÓhjÔ.”:˜b¤$×'Ò'ŒˆBŒ¨QÔ.Ó9dùs   ‚	;�+;c              3   óB   "  € T F  qP                  R 4      x € K  	  R# 5i©Ú
tool_callsN)r9   r:   s   & r&   r=   r>   ‡   s   é € Ð9dÑ[cÐTW¿'¹'À,×:OÐ:OÓ[cùs   ‚Úfrom_message_idÚidÚto_message_idÚ	from_roler7   Úto_roleÚgap_msiè  c                 óV   € \         P                  ! V \        R 7      P                  4       # ))Útz)r   Úfromtimestampr   Ú	isoformat)Útss   &r&   Ú<lambda>Ú!_export_timings.<locals>.<lambda>�   s   € ”X×+Ò+¨B´3Ô7×AÑAÔCr(   ÚsourceÚmessage_timestampsÚ	availableÚcompleteFÚunavailable_reasonÚno_timestamped_messagesÚmissingÚfirst_message_atÚlast_message_atÚwall_clock_msÚlargest_gap_msc              3   ó2   "  € T F  qR ,          x € K  	  R# 5i)rL   N© )r;   Úis   & r&   r=   r>   ˜   s   é € Ð=±9¨a Ÿkšk³9ùs   ‚Úrole_countsÚtool_result_countÚtoolÚtool_calls_emittedÚ	intervalséÿÿÿÿ)NN)r   r9   r   ÚsumÚ	itertoolsÚpairwiseÚmaxÚroundÚboolrB   r3   )r0   r1   r<   rQ   Útimestampedrb   re   ÚprevÚprev_tsÚnxtÚnxt_tsrf   ÚisoÚfirst_tsÚlast_tss   &&             r&   Ú_export_timingsrv   x   sö  € ñ )1ó e© Ü)¨#¯'©'°+Ó*>È:ÔVÐV�rô �C“9©€Kð eäÑPÁxÓPÓP€KÜñ lÙ9dÑ[cÔ9dóló lÐô -6×,>Ò,>¸{Ô,Kö	Mñ -LÑ
(‰/ˆ4™=˜Cð 	˜4Ÿ8™8 D›>¨?¸C¿G¹GÀD»MØ�T—X‘X˜fÓ% y°#·'±'¸&³/Ø”#�aœ Õ 0°DÕ8Ó9Ó:óñ -Lð	 ó Mñ
 D€CßCN˜ Q�¨Õ*¨K¸­O¸AÕ,>Ñ?ÐT`Ñ€HàÐ&Ø”T˜+Ó&Ø�EØ§k™dÐ7PØ˜{¬C°Ó,<¸iÌÈXËÔY\Ð]hÓYiÕIiÐjØ¨XÒ-A™C œMÀtØ¨7Ò+>™3˜wœ<ÀDØÇ{œ˜Q¤ wÕ'9¸TÕ&AÓ BÔCÐX\ØÇœ#Ñ=±9Ó=Ô=ÐPTØ”t˜KÓ(Ø˜[Ÿ_™_¨V°QÓ7ØÐ0Ø�Yðð ùòeùõ
Ms   …"G1¬G1Á;A8G6
c                   ó"  a € ] tR t^ t o Rt]R 4       tR tR t]	V 3R lR l4       t
]	V 3R lR l4       tRGV 3R	 lR
 lltRHV 3R lR lltRIV 3R lR lltV 3R lR ltRHV 3R lR llt]tRHV 3R lR lltRJV 3R lR lltRKV 3R lR lltRKV 3R lR lltRKV 3R lR lltRLV 3R lR lltR R!/V 3R" lR# lltV 3R$ lR% lt]V 3R& lR' l4       t]V 3R( lR) l4       t]V 3R* lR+ l4       t]	V 3R, lR- l4       t]	V 3R. lR/ l4       t]V 3R0 lR1 l4       tRMt RNt!]	V 3R2 lR3 l4       t"V 3R4 lR5 lt#]	V 3R6 lR7 l4       t$]	V 3R8 lR9 l4       t%V 3R: lR; lt&V 3R< lR= lt'V 3R> lR? lt(V 3R@ lRA lt)]V 3RB lRC l4       t*V 3RD lRE lt+RFt,V t-R# )OÚSessionPortabilityMixinu<   See module docstring â€” mixin for SessionDB (Port cluster).c                óÂ  € V P                  R VR,          34      P                  4       pV F°  p\        VR,          / R7      ;'       g    / P                  R/ 4      pVP                  R4      VR,          8w  d   KP  VP                  R4      pV'       d   WTP                  R4      8X  g*   V'       d   Kˆ  VP                  R4      VR,          8X  g   K§  VR,          u # 	  R# )	zQSELECT id, origin_json FROM sessions WHERE source = ? AND origin_json IS NOT NULLrd   Úorigin_json©ÚdefaultÚimported_fromÚforeign_session_idÚpathrH   N)ÚexecuteÚfetchallr   r9   )ÚconnÚoriginÚrowsÚrowÚimportedÚ
foreign_ids   &&    r&   Ú_find_foreign_import_on_connÚ4SessionPortabilityMixin._find_foreign_import_on_conn£   sº   € à�|‰|ÐoØ# F�^Ð-ó/ß/7©x«zð 	ãˆCÜ'¨¨MÕ(:ÀBÔG×MÐMÈ2×RÑRÐSbÐdfÓgˆHØ�|‰|˜FÓ# v¨f¥~Ô5ÙØŸ™Ð$8Ó9ˆJß 
¯l©lÐ;OÓ.PÔ Pß&™J¨8¯<©<¸Ó+?À6È&Å>Ö+QØ˜4•yÒ ñ ñ r(   c                ó’   € V P                  4       ;_uu_ 4       pV P                  W!4      uuR R R 4       #   + '       g   i     R # ; i©N)Ú	_read_ctxrˆ   )Úselfrƒ   r‚   s   && r&   Úfind_foreign_importÚ+SessionPortabilityMixin.find_foreign_import±   s.   € Ø�^‰^×Ô Ø×4Ñ4°TÓB÷ ××Óús	   ™5µA	c               óì   a aaaaa	€ \        ^R7      o	S P                  RS	RSR,          RSRVRV/.4      w  opV'       d   \        V^ ,          R,          4      hVVVV V	V3R	 lpS P                  V4      # )
a  Adopt or mint a foreign snapshot in one transaction, including its provenance.

BEGIN IMMEDIATE serializes duplicate clicks across connections/processes.
Reuse the portability validator and message writer so counters and FTS
obey the same contract as ordinary transcript imports.
)Úhex_lenrH   rT   rd   ÚtitleÚcwdr0   Úerrorc                 ór  <€ SP                  V S4      pV'       d   R VRR/# S^ ,          pV P                  RS34      P                  4       '       d   S RSRR  R2VR,          R&   SP                  WR,          VR	,          S4       V P                  R
\        P
                  ! RS/4      SS34       R SRR/# )r1   Úalready_importedTz&SELECT 1 FROM sessions WHERE title = ?z (NÚ)Úsessionr’   r0   zBUPDATE sessions SET origin_json = ?, profile_name = ? WHERE id = ?r}   Fiôÿÿÿ)rˆ   r€   ÚfetchoneÚ_import_session_rowÚjsonÚdumps)	r‚   ÚexistingÚitemÚ
normalizedrƒ   Úprofiler�   r1   r’   s	   &  €€€€€€r&   Ú_doÚ;SessionPortabilityMixin.import_foreign_history.<locals>._doÃ   sÆ   ø€ Ø×8Ñ8¸¸vÓFˆHßØ$ hÐ0BÀDÐIÐIð ˜a•=ˆDØ�|‰|ÐDÀuÀhÓO×XÑX×ZÒZØ.3¨W°B°zÀ#À$Ð7GÐ6HÈÐ+J��Y• Ñ(Ø×$Ñ$ T°	­?¸DÀÕ<LÈjÔYØ�L‰LÐ]ÜŸ*š* o°vÐ%>Ó?ÀÈ*ÐUôWà  *Ð.@À%ÐHÐHr(   )r   Ú_validate_import_payloadÚ
ValueErrorÚ_execute_write)
r�   rƒ   r0   r’   r“   r    Úerrorsr¡   rŸ   r1   s
   ff&d$d  @@r&   Úimport_foreign_historyÚ.SessionPortabilityMixin.import_foreign_historyµ   s€   ý€ ô $¨BÔ/ˆ
Ø!×:Ñ:Ø�:˜x¨°­¸À%Ø�C˜ Xð/ð<0ó 1Ñˆ
�F÷ Ü˜V A�Y wÕ/Ó0Ð0÷	Iò 	Ið ×"Ñ" 3Ó'Ð'r(   c                ó    <€ V ^8„  d   QhRS[ /# ©r   r#   )r$   )r%   Ú__classdict__s   "€r&   r'   Ú$SessionPortabilityMixin.__annotate__Ô   s   ø€ ÷ -ñ -¡cñ -r(   c                ó°   a € S P                   f=   S P                  \        4      R,          pRP                  V 3R lV 4       4      S n         S P                   # )z‚``s.``-prefixed SELECT list of every SCHEMA_SQL ``sessions`` column except
prompt storage internals (the compact_rows projection).Úsessionsú, c              3   óR   <"  € T F  qSP                   9  g   K  R V 2x € K  	  R# 5i)zs.N)Ú_SESSION_COMPACT_EXCLUDED)r;   ÚnameÚclss   & €r&   r=   Ú@SessionPortabilityMixin._compact_session_cols.<locals>.<genexpr>Ù   s'   øé € ð 6Ù(0 À×@]Ñ@]Ñ4]”�"�T�F•«ùs   ƒ'š')Ú_session_compact_cols_sqlÚ_parse_schema_columnsr   Újoin)r³   Údeclareds   f r&   Ú_compact_session_colsÚ-SessionPortabilityMixin._compact_session_colsÓ   sR   ø€ ð ×(Ñ(Ò0Ø×0Ñ0´Ó<¸ZÕHˆHØ,0¯I©Iô 6Ù(0ó6ó -ˆCÔ)ð ×,Ñ,Ð,r(   c                ó6   <€ V ^8„  d   QhRS[ S[S[3,          /# rª   )r3   r$   r   )r%   r«   s   "€r&   r'   r¬   ß   s   ø€ ÷ ñ ™t¡C© H�~ñ r(   c                ód   € V P                  V4      p\        VP                  RR4      4      VR&   V# )z?Session row dict with ``_preview_raw`` shaped into ``preview``.Ú_preview_rawr*   Úpreview)Ú_session_row_dictr   Úpop)r³   r…   r,   s   && r&   Ú	_rich_rowÚ!SessionPortabilityMixin._rich_rowÞ   s2   € ð ×!Ñ! #Ó&ˆÜ% a§e¡e¨N¸BÓ&?Ó@ˆˆ)‰Øˆr(   c                ó&   <€ V ^8„  d   QhRS[ RS[/# )r   Úsqlr#   )r$   r2   )r%   r«   s   "€r&   r'   r¬   å   s   ø€ ÷ 8ñ 8™cð 8±ñ 8r(   c                ó®   € V P                  4       ;_uu_ 4       pVP                  W4      P                  4       uuRRR4       #   + '       g   i     R# ; i)z^Pure-read query via ``_read_ctx()`` (never the writer lock: turn persistence must not convoy).N)rŒ   r€   r�   )r�   rÄ   Úparamsr‚   s   &&& r&   Ú
_read_rowsÚ"SessionPortabilityMixin._read_rowså   s5   € à�^‰^×Ô Ø—<‘< Ó,×5Ñ5Ó7÷ ××Óús   ™AÁA	c                óL   <€ V ^8„  d   QhRS[ RS[S[S[S[3,          ,          /# )r   Úinclude_archivedr#   )rm   r2   r3   r$   r   )r%   r«   s   "€r&   r'   r¬   ê   s+   ø€ ÷ ñ ±dð ÁtÉDÑQTÑVYÐQYÍNÕG[ñ r(   c                ó  € RpV'       g
   VR,          pV P                  RV R24      pV Uu. uFF  pRVR,          R\        VR,          ;'       g    ^ 4      R\        VR,          ;'       g    ^ 4      /NKH  	  up# u upi )z­Distinct non-empty session cwds with usage stats, for repo discovery. Aggregates
across ALL history; children/branches count (a worktree session is a real
workspace signal).z#cwd IS NOT NULL AND TRIM(cwd) != ''z AND archived = 0zsSELECT cwd AS cwd, COUNT(*) AS sessions, MAX(COALESCE(ended_at, started_at, 0)) AS last_active FROM sessions WHERE z GROUP BY cwdr“   r®   Úlast_active)rÇ   ÚintÚfloat)r�   rÊ   r    r„   Úrs   &&   r&   Údistinct_session_cwdsÚ-SessionPortabilityMixin.distinct_session_cwdsê   s•   € ð 6ˆßØÐ(Õ(ˆEØ�‰ð#Ø#( '¨ð8ó
ˆñ
 óÙ�Að ˜˜%� *¬c°!°Jµ-×2DÐ2DÀ1Ó.EÀ}ÔV[Ð\]Ð^kÕ\l×\qÐ\qÐpqÓVrÓsÙñð 	ùò s   ­#A<ÁA<Á-A<c                óX   <€ V ^8„  d   QhRS[ RS[RS[RS[S[S[ S[3,          ,          /# )r   Újob_idÚlimitÚoffsetr#   )r$   rÍ   r2   r3   r   )r%   r«   s   "€r&   r'   r¬   ø   sB   ø€ ÷ Pñ P©ð P±Sð PÁsð PÑSWÑX\Ñ]`ÑbeÐ]eÕXfÕSgñ Pr(   c                ó"  € \        RV R24      w  rE\        V4      w  rg\        R\         R2R\         R2RR\
         2R	7      pV P                  VR
VRVRVRVRVRVRV/4      p	V	 U
u. uF  p
/ V P                  V
4      CRV/CNK  	  up
# u up
i )aµ  Run sessions of one cron job, newest first, in the ``list_sessions_rich`` row shape,
stamped with ``cron_job_id`` and ``cron_execution_id`` (None for a pre-unified run).

Pre-unified runs are flat ``cron_{job_id}_{timestamp}`` sessions: a ``[prefix,
prefix_hi)`` id range. Unified-runtime runs keep their runtime-minted ``local-*`` id, which
must not change (exact-retry recovery re-derives it), but the scheduler principal admitted
each under ``cron:<job>:<execution>``: a range of ``idx_session_admissions_cron_request``.
Both scans scale with this job's runs, never with total cron history or with every local
session's policy receipt, and skip ``list_sessions_rich``'s compression-chain CTE.

Limitation (legacy runs had it too): only a run's FIRST session is listed. A run that
compressed continues in a child session this does not return, and the row's liveness
(``scheduler_owned``) and detail identity follow that first session, not the tip.Úcron_Ú_zs.*, z AS cron_execution_idzs.source = 'cron' AND s.id IN (r—   zZ
            ORDER BY s.started_at DESC, s.id DESC
            LIMIT :limit OFFSET :offsetr+   ©r"   ÚprefixÚ	prefix_hiÚ
request_loÚ
request_hirÓ   rÔ   rÕ   Úcron_job_id)r   r   r.   Ú_CRON_EXECUTION_SQLÚ_CRON_RUN_IDS_SQLÚ_PROMPT_RESOLVED_SQLrÇ   rÁ   )r�   rÓ   rÔ   rÕ   rÚ   rÛ   rÜ   rÝ   Úqueryr„   r…   s   &&&&       r&   Úlist_cron_job_runsÚ*SessionPortabilityMixin.list_cron_job_runsø   sÈ   € ô )¨5°°¸Ð):Ó;ÑˆÜ!3°FÓ!;Ñˆ
ÜØÔ'Ð(Ð(=Ð>ÐBaÔbsÐatÐtuÐ@vØjØ/Ô0DÐ/EÐFô
ˆð
 �‰˜u x°¸ÀiÐQ]Ð_iØ'3°ZÀÈ6ÐSZÐ\aÐckÐmsð'uó vˆáJNÓOÉ$À3Ð>�4—>‘> #Ó&Ð>¨°vÔ>É$ÑOÐOùÒOs   Á) Bc                óL   <€ V ^8„  d   QhRS[ RS[S[S[ S[3,          ,          /# )r   r1   r#   )r$   r	   r3   r   )r%   r«   s   "€r&   r'   r¬     s,   ø€ ÷ Uñ U©Cð U±H¹TÁ#ÁsÀ(½^Õ4Lñ Ur(   c                ó¢  € \        V4      pVe   RVRR/# V P                  R\        ,           R,           \        V34      pRpV'       dj   \	        V^ ,          R,          4      pVfM   \        V^ ,          R,          \        4      '       d)   \	        V^ ,          R,          V^ ,          R,          4      pV'       d   RV^ ,          RV^,          /# R# )a  ``{"cron_job_id", "cron_execution_id"}`` of a cron run session, else None: a legacy id
names its job (no execution), a unified-runtime run is one probe of its scheduler admission
(and, when its request id is ambiguous, of the job its creation receipt's policy names).NrÞ   Úcron_execution_idzSELECT request_id, zl AS policy_job FROM session_admissions WHERE principal_id = ? AND target_session_id = ? ORDER BY seq LIMIT 1Ú
request_idÚ
policy_job)r   rÇ   Ú_CRON_POLICY_JOB_SQLr   r   rA   r$   )r�   r1   Ú
legacy_jobr„   Úruns   &&   r&   Úcron_run_identityÚ)SessionPortabilityMixin.cron_run_identity  sÆ   € ô )¨Ó4ˆ
ØÒ!Ø! :Ð/BÀDÐIÐIØ�‰Ø!Ô$8Õ8ð <Uõ UÜWhÐjtÐVuówˆð ˆßÜ'¨¨Q­°Õ(=Ó>ˆCØŠ{œz¨$¨q­'°,Õ*?Ä×EÒEÜ+¨D°­G°LÕ,AÀ4ÈÅ7È<ÕCXÓY�ßGJ�˜s 1�vÐ':¸CÀ½FÐCÐTÐPTÐTr(   c          	      óR   <€ V ^8„  d   QhRS[ RS[RS[S[S[ S[3,          ,          /# )r   r1   Úcompact_rowsr#   ©r$   rm   r	   r3   r   )r%   r«   s   "€r&   r'   r¬   "  s:   ø€ ÷ jñ j±ð jÁ4ð jÑT\Ñ]aÑbeÑgjÐbjÕ]kÕTlñ jr(   c                óH   € V P                  V.VR7      P                  V4      # )zÁOne session with the ``list_sessions_rich`` enriched columns, or None.
``compact_rows=True`` omits the ``system_prompt`` blob. Public alias:
:meth:`get_session_rich_row` (web server hydration).©rð   )Ú_get_session_rich_rows_batchr9   )r�   r1   rð   s   &&&r&   Ú_get_session_rich_rowÚ-SessionPortabilityMixin._get_session_rich_row"  s(   € ð ×0Ñ0°*°ÈLÐ0ÓY×]Ñ]Ð^hÓiÐir(   c                óR   <€ V ^8„  d   QhRS[ RS[S[S[S[S[3,          3,          /# )r   rð   r#   )rm   r3   r$   r   )r%   r«   s   "€r&   r'   r¬   *  s8   ø€ ÷ Vñ VÁdð VÑW[Ñ\_ÑaeÑfiÑknÐfnÕaoÐ\oÕWpñ Vr(   c           	     óR  € V Uu. uF  q3'       g   K  VNK  	  ppV'       g   / # Rp\        V4      V8”  dL   / p\        ^ \        V4      V4       F-  pVP                  V P                  WGWu,            VR7      4       K/  	  V# V P	                  4        \        V'       d   V P                  4       MRRRP                  R V 4       4       R2V'       d   RMR	\         2R
7      p\        V P                  V P                  W„4      4       U	u/ uF  q™R,          V	bK  	  up	# u upi u up	i )zŠEnriched rows for many sessions in one query, keyed by id; missing ids are absent
(a page of compression tips resolves in one round trip).é„  ró   zs.*z	s.id IN (Ú,c              3   ó&   "  € T F  pR x € K	  	  R# 5i©Ú?Nr`   ©r;   rØ   s   & r&   r=   ÚGSessionPortabilityMixin._get_session_rich_rows_batch.<locals>.<genexpr>;  s   é € ÐYkÑgjÐbcÕZ]Ógjùó   ‚r—   Nr¯   rÙ   rH   )rB   ÚrangeÚupdaterô   Úflush_token_countsr.   r¹   r·   rá   ÚmaprÁ   rÇ   )
r�   Úsession_idsrð   ÚsidÚidsÚ_CHUNKÚresultÚstartrâ   r,   s
   &&&       r&   rô   Ú4SessionPortabilityMixin._get_session_rich_rows_batch*  s  € ñ *Ó1™k�s«S�sˆs™kˆÐ1ßØˆIð ˆÜˆs‹8�fÔØ02ˆFÜ˜q¤# c£(¨FÖ3�Ø—‘˜d×?Ñ?ÀÈ%Í.Ð@YÐhtÐ?ÓuÖvñ 4àˆMà×ÑÔ!Üß,8ˆD×&Ñ&Ô(¸eÀyÐQT×QYÑQYÑYkÑgjÓYkÓQkÐPlÐlmÐEnß".™$°bÔ9MÐ8NÐ4Oô
ˆô %(¨¯©¸¿¹ÈÓ8SÔ$TÓUÑ$T˜q�$•˜’
Ñ$TÑUÐUùò# 2ùò" Vs   …	D“DÄ
D$c                óL   <€ V ^8„  d   QhRS[ RS[S[S[S[3,          ,          /# )r   rÔ   r#   )rÍ   r2   r3   r$   r   )r%   r«   s   "€r&   r'   r¬   @  s)   ø€ ÷ +ñ +±Cð +Á$ÁtÉCÑQTÈHÅ~ÕBVñ +r(   c                óŽ   € V P                  R\        \        \        V4      34      pV Uu. uF  p\	        V4      NK  	  up# u upi )a  Titled sessions whose first user turn was a ``/skill`` invocation or a gateway
auto-load scaffold (their titles describe the expanded skill body, not the
request). Returns ``id``, ``title`` and the first-turn ``content`` so callers can
re-derive what was typed. Newest first.a  
                SELECT s.id, s.title, m.content
                FROM sessions s
                JOIN messages m ON m.id = (
                    SELECT m2.id FROM messages m2
                    WHERE m2.session_id = s.id AND m2.role = 'user'
                      AND m2.content IS NOT NULL
                    ORDER BY m2.timestamp, m2.id LIMIT 1
                )
                WHERE s.title IS NOT NULL AND (m.content LIKE ? OR m.content LIKE ?)
                ORDER BY s.started_at DESC
                LIMIT ?
                )rÇ   r   r
   rÍ   r3   )r�   rÔ   r„   r…   s   &&  r&   Úlist_skill_scaffolded_sessionsÚ6SessionPortabilityMixin.list_skill_scaffolded_sessions@  sH   € ð
 �‰ð  ô .Ô/JÌCÐPUËJÐWóYˆñ &*Ó*¡T˜c”�S–	¡TÑ*Ð*ùÒ*s   «Ac          
      ó^   <€ V ^8„  d   QhRS[ S[S[3,          RS[RS[RS[ S[S[3,          /# )r   r˜   Úinclude_compactedÚinclude_inactiver#   )r3   r$   r   rm   )r%   r«   s   "€r&   r'   r¬   V  sA   ø€ ÷ fñ f¡d©3±¨8¥nð fÉð fÙ)-ðfÙ:>¹sÁC¸x½.ñfr(   c           	     ój   € V P                  VR ,          W2R7      p/ VCRVR\        WAR ,          4      /C# )rH   )r  r  r0   Útimings)Úget_messagesrv   )r�   r˜   r  r  r0   s   &&&& r&   Ú_with_messagesÚ&SessionPortabilityMixin._with_messagesV  s=   € à×$Ñ$ W¨T¥]ÐEUÐ$Ó{ˆØe�'Ðe˜: x°¼OÈHÐ^bÕVcÓ<dÑeÐer(   c                óX   <€ V ^8„  d   QhRS[ RS[RS[RS[S[S[ S[3,          ,          /# ©r   r1   r  r  r#   rñ   )r%   r«   s   "€r&   r'   r¬   [  s>   ø€ ÷ fñ f©ð fÁð fÙ)-ðfÙ:BÁ4ÉÉSÈÅ>Õ:Rñfr(   c                ó\   € V P                  V4      pV'       d   V P                  WBV4      # R# )aì  Export a single session with all its messages as a dict. ``include_compacted`` adds the turns
in-place compaction archived (the history the user still sees); it stays off for payloads that go
back through :meth:`import_sessions`, because that projection is deduped and ordered for display, and
importing it would make those turns live context. ``include_inactive`` exports every row in storage
order with its ``active``/``compacted`` flags, which :meth:`import_sessions` restores as archived.N)Úget_sessionr  )r�   r1   r  r  r˜   s   &&&& r&   Úexport_sessionÚ&SessionPortabilityMixin.export_session[  s0   € ð ×"Ñ" :Ó.ˆßT[ˆt×"Ñ" 7Ð?OÓPÐeÐaeÐer(   c                óX   <€ V ^8„  d   QhRS[ RS[RS[RS[S[S[ S[3,          ,          /# r  rñ   )r%   r«   s   "€r&   r'   r¬   e  s;   ø€ ÷ 
ñ 
±ð 
Éð 
Ù15ð
ÙBJÉ4ÑPSÑUXÐPXÍ>ÕBZñ
r(   c                ó¤  a aa€ S P                  V4      pV'       g   R# VVV 3R lV 4        Uu. uF  pV'       g   K  VNK  	  ppV'       g   R# V UUu. uF%  qUP                  R4      ;'       g    .  F  qwNK  	  K'  	  ppp/ VR	,          CRTRV Uu. uF  qUR,          NK  	  upR\        V4      RVR\        W�4      /C# u upi u uppi u upi )
z^Export a compression lineage as one logical session dict (flags as in :meth:`export_session`).Nc              3   óJ   <"  € T F  pSP                  VSS4      x € K  	  R # 5ir‹   )r  )r;   r  r  r  r�   s   & €€€r&   r=   ÚASessionPortabilityMixin.export_session_lineage.<locals>.<genexpr>k  s,   øé € ð $<Ù/:¨ð %)×$7Ñ$7¸Ð=NÐP`×$aÐ$aÛ/:ùs   ƒ #r0   ÚsegmentsÚlineage_session_idsrH   Úmessage_countr  rg   )Úget_compression_lineager9   rB   rv   )	r�   r1   r  r  Úlineage_idsÚsegr"  r<   r0   s	   f&ff     r&   Úexport_session_lineageÚ.SessionPortabilityMixin.export_session_lineagee  så   ú€ ð ×2Ñ2°:Ó>ˆßÙö$<Ù/:ô$<ó Dñ $<˜CÜ?B÷ �Cñ $<ˆð DçÙÙ#+ÔS¡8˜C¿¹À
Ó8K×8QÐ8QÈrÒ8Q°’CÑ8Q‘C¡8ˆÑSð
Ø�r�lð
Ø&¨Ø!¹Ó#B¹°#¨§I I¹Ñ#BÀOÔUXÐYaÓUbØ˜ )¬_¸XÓ-Rñ
ð 	
ùòDùó Tùò $Cs   ¯
C¾CÁCÁ1CÂCNc                óf   <€ V ^8„  d   QhRS[ R,          RS[RS[RS[S[S[ S[3,          ,          /# )r   rT   Nr  r  r#   )r$   rm   r2   r3   r   )r%   r«   s   "€r&   r'   r¬   v  sB   ø€ ÷ yñ y¡ t¥ð yÁtð yÙ%)ðyÙ6:¹4ÁÁSÀ½>Õ6Jñyr(   c                ó®  € V P                  VRR7      pV'       d#   V Uu. uF  qPP                  VRV4      NK  	  up# V Uu/ uF  qUR,          . bK  	  pp\        V4      pV P                  VR4      p\	        ^ \        V4      R4       Fv  p	WyV	R,            p
V P                  RRP                  R	 V
 4       4       R
V R2V
4      pV F3  pWlR,          ,          P                  V P                  VRRR7      4       K5  	  Kx  	  V Uu. uF8  p/ VCRWeR,          ,          R\        WeR,          ,          VR,          4      /CNK:  	  up# u upi u upi u upi )aC  Export all sessions (with messages) as dicts, e.g. for JSONL backup (flags as in
:meth:`export_session`; that display read dedupes per session, so it skips the batched read).
Backups that go back through :meth:`import_sessions` pass ``include_inactive`` so
compaction-archived turns survive the round trip as archived rows.i † )rT   rÔ   TrH   Frù   z,SELECT * FROM messages WHERE session_id IN (rú   c              3   ó&   "  € T F  pR x € K	  	  R# 5irü   r`   rþ   s   & r&   r=   Ú5SessionPortabilityMixin.export_all.<locals>.<genexpr>†  s   é € ÐG[ÑUZÐPQÍÓUZùr   z) z ORDER BY session_id, idr1   r  )Úwarn_contextÚsummary_flagr0   r  )Úsearch_sessionsr  r2   Ú_active_clauser  rB   Ú	_read_allr·   ÚappendÚ_row_to_message_dictrv   )r�   rT   r  r  r®   r˜   Úmessages_by_sessionr  Úactive_clauser
  Úchunkr„   r…   s   &&&&         r&   Ú
export_allÚ"SessionPortabilityMixin.export_allv  s  € ð ×'Ñ'¨v¸VÐ'ÓDˆßÙX`ÓaÑX`ÈW×'Ñ'¨°Ð7GÖHÑX`ÑaÐaÙ@HÓIÁ°W t�}¨bÒ0ÁÐÐIÜÐ.Ó/ˆØ×+Ñ+Ð,<¸eÓDˆä˜1œc +Ó.°Ö4ˆEØ e¨c¥kÐ2ˆEØ—>‘>Ø>¸s¿x¹xÑG[ÑUZÓG[Ó?[Ð>\Ð\^Ø �/Ð!9ð;àóˆDó
 �Ø#¨Õ$5Õ6×=Ñ=Ø×-Ñ-¨cÀÐ]aÐ-Óböó ñ 5ñ pxóyÙowÐdkð`�7ð `˜JÐ(;ÀD½MÕ(JØœOÐ,?ÈÅÕ,NÐPWÐX\ÕP]Ó^ô`Ùowñyð 	yùò! bùÚIùòys    EÁEÄ>EÚretire_donorTc          
      óH   <€ V ^8„  d   QhRS[ RS[RS[RS[S[S[ 3,          /# )r   Údonor_dbr1   r:  r#   )r   r$   rm   r3   )r%   r«   s   "€r&   r'   r¬   ‘  s=   ø€ ÷ 3Nñ 3N±3ð 3NÁCð 3NÑZ^ð 3NÑjnÑorÑtwÐowÕjxñ 3Nr(   c          
     óB  a a€ SP                  VRR7      pV'       g   RRRRRRRRV: R	2/# VP                  R
4      ;'       g    V.pRpV F’  pVP                  R4      pV'       d   S P                  V4      f   K1  \        VP                  R4      ;'       g    . 4      p	\        S P	                  VRR7      4      p
Wš8”  g   Ky  Rp\
        P                  RW‰V
4       K”  	  S P                  V Uu. uF  p\        V4      NK  	  up4      p\        VP                  R4      ;'       g    ^ 4      p\        VP                  R4      ;'       g    ^ 4      pVP                  RR4      ;'       d    WÍ,           \        V4      8H  pV'       g2   \
        P                  RW,V\        V4      VP                  R4      4       RpV'       dM   V'       dE   V'       g=   \        ;QJ d     VV 3R lV 4       F  '       d   K   RM	  RM! VV 3R lV 4       4      p/ VCRVRV/C# u upi )u2  Adopt *session_id*'s full compression lineage from *donor_db* (stranded-bot-session
heal: a profile bot's rows accumulated in the DEFAULT profile's state.db before the
desktop routed session RPCs by target session). Pure composition
``donor_db.export_session_lineage()`` -> ``self.import_sessions()``: runtime
fields reset, already-present ids skipped (idempotent). Every message row is carried
with its archived state, so turns in-place compaction archived stay visible here and
stay out of model context. With ``retire_donor`` and a complete adoption, donor rows
are ARCHIVED (never deleted) with
``end_reason='adopted_by_profile'`` â€” deliberately NOT in the recoverable set, so
resurrection cannot undo an adoption. Returns the ``import_sessions`` dict plus
``adopted`` and ``donor_retired`` (True only when EVERY segment retired).

Once routing was fixed, the profile backend correctly received the RPCs but had no such session, so
the same chat 4001'd for the opposite reason. This method moves the conversation to where routing
now looks for it. See #93091, #93296.
T©r  ÚokFÚadoptedÚdonor_retiredr”   úsession z not found in donor storer"  rH   r0   uf   adoption divergence: donor segment %s has %d messages, local copy has %d â€” donor will NOT be retiredr†   ÚskippedzSadoption of %s did not complete: imported=%s skipped=%s of %s segment(s); errors=%sr¦   c              3   ó†   <"  € T F6  qP                  R 4      '       g   K  SP                  SVR ,          4      x € K8  	  R# 5i)rH   N)r9   Ú_retire_donor_segment)r;   r'  r<  r�   s   & €€r&   r=   ÚESessionPortabilityMixin.adopt_session_lineage_from.<locals>.<genexpr>Ã  s7   øé € ÐuÑ[cÐTW×gnÑgnÐos×gtÔ O × :Ñ :¸8ÀSÈÅY× OÐ OÓ[cùs
   ƒA !A)r(  r9   r  rB   r  ÚloggerÚwarningÚimport_sessionsr3   rÍ   Úall)r�   r<  r1   r:  Úpayloadr"  Údonor_aheadr'  Úseg_idÚdonor_countÚlocal_countr	  r†   rC  r@  rA  s   ff&$            r&   Úadopt_session_lineage_fromÚ2SessionPortabilityMixin.adopt_session_lineage_from‘  sß  ù€ ð& ×1Ñ1°*ÈtÐ1ÓTˆßØ˜% ¨E°?ÀEØ˜x¨
¡~Ð5NÐOðQð Qà—;‘;˜zÓ*×7Ð7¨w¨iˆð
 ˆÛˆCØ—W‘W˜T“]ˆFß˜T×-Ñ-¨fÓ5Ò=ÙÜ˜cŸg™g jÓ1×7Ð7°RÓ8ˆKÜ˜d×/Ñ/°ÈÐ/ÓNÓOˆKØÖ(Ø"�Ü—‘ð  QØRXÐgrötñ ð ×%Ñ%¹HÓ&E¹H°S¤t¨C¦y¹HÑ&EÓFˆÜ�v—z‘z *Ó-×2Ð2°Ó3ˆÜ�f—j‘j Ó+×0Ð0¨qÓ1ˆØ—*‘*˜T 5Ó)×SÐS¨xÕ/AÄcÈ(ÃmÑ.SˆßÜ�N‰NÐpØ%°¼#¸h»-ÈÏÉÐT\ÓI]ô_ð ˆß—|¯Kß›CÕuÑ[cÓuŸCŸCšCÕuÑ[cÓuÓuˆMØM�&ÐM˜) W¨o¸}ÑMÐMùò 'Fs   Ã2Hc                ó,   <€ V ^8„  d   QhRS[ RS[RS[/# )r   r<  rM  r#   )r   r$   rm   )r%   r«   s   "€r&   r'   r¬   Æ  s"   ø€ ÷ ñ ©cð ¹3ð Á4ñ r(   c                óx  €  \        VP                  VRR7      4      p\        V P                  VRR7      4      pW48”  d   \        P                  RW#V4       R# VP	                  V4       VP                  VR4       VP                  VRRR7       R#   \         d    \        P                  RTRR7        R# i ; i)	u¼  Archive one adopted donor segment; False when skipped or failed. TOCTOU close-out:
the divergence guard used EXPORT-TIME counts; re-read both stores right before
stamping so donor growth never lands behind a non-recoverable archive
(equal-count CONTENT divergence is accepted â€” bytes stay in the donor either way).
A retirement failure must not fail the adoption (a later resume retries
idempotently), but never claims success it didn't have.Tr>  uo   adoption divergence at retire time: donor segment %s grew to %d messages (local %d) â€” leaving donor unretiredFÚadopted_by_profile)Únotifyz0failed to retire donor segment %s after adoption)Úexc_info)rB   r  rG  rH  Úreopen_sessionÚend_sessionÚset_session_archivedÚ	Exception)r�   r<  rM  Ú	donor_nowÚ	local_nows   &&&  r&   rE  Ú-SessionPortabilityMixin._retire_donor_segmentÆ  s»   € ð	Ü˜H×1Ñ1°&È4Ð1ÓPÓQˆIÜ˜D×-Ñ-¨fÀtÐ-ÓLÓMˆIØÔ$Ü—‘ð.Ø/5À)ôñ ð ×#Ñ# FÔ+Ø× Ñ  Ð)=Ô>à×)Ñ)¨&°$¸uÐ)ÔEÙøÜô 	Ü�N‰NÐMÈvÐ`dˆNÔeÚð	ús   ‚AB Á7B Â#B9Â8B9c                ó<   <€ V ^8„  d   QhRS[ RS[RS[S[,          /# ©r   ÚvalueÚfieldr#   ©r   r$   r	   )r%   r«   s   "€r&   r'   r¬   ä  s&   ø€ ÷ 6ñ 6¡Cð 6±ð 6¹Á½ñ 6r(   c                óV   € V e   \        V \        4      '       d   V # \        V R24      h)Nz must be a string)rA   r$   r¤   )r`  ra  s   &&r&   Ú_import_text_or_noneÚ,SessionPortabilityMixin._import_text_or_noneã  s+   € àŠ=œJ u¬c×2Ò2ØˆLÜ˜E˜7Ð"3Ð4Ó5Ð5r(   c                ó<   <€ V ^8„  d   QhRS[ RS[RS[S[,          /# r_  )r   r$   r	   rÍ   )r%   r«   s   "€r&   r'   r¬   ê  s+   ø€ ÷ Eñ E¡3ð E©sð E±xÁµ}ñ Er(   c                óv   €  V f   R # \        V 4      #   \        \        3 d   p\        T R24      ThR p?ii ; i)Nz must be an integer)rÍ   Ú	TypeErrorr¤   )r`  ra  Úexcs   && r&   Ú_import_int_or_noneÚ+SessionPortabilityMixin._import_int_or_noneé  sG   € ð	EØ š=�4Ð8¬c°%«jÐ8øÜœ:Ð&ô 	EÜ ˜wÐ&9Ð:Ó;ÀÐDûð	Eús   ‚ ˆ
 “8¤3³8c                ó<   <€ V ^8„  d   QhRS[ RS[RS[S[,          /# ©r   r`  r   r#   rb  )r%   r«   s   "€r&   r'   r¬   ñ  s&   ø€ ÷ ñ ¡sð ±#ð ¹(Á3½-ñ r(   c                ó¬  a€ W3.pV'       dÇ   VP                  4       w  po\        V\        4      '       d   \        P                  ! V4      '       g   S# \        V\
        4      '       d,   VP                  V3R lVP                  4        4       4       K�  \        V\        4      '       g   K¨  VP                  V3R l\        V4       4       4       KÎ  R# )zÓFirst ``path`` of a NaN/inf number anywhere in decoded JSON data, else None.

Iterative walk (a recursive visitor would overflow on crafted nesting); cycles
can't arrive through ``json.loads`` but guard anyway.
c              3   ó:   <"  € T F  w  rVS R V 23x € K  	  R# 5i)Ú.Nr`   ©r;   ÚkeyÚchildÚcurrent_paths   &  €r&   r=   ÚBSessionPortabilityMixin._import_non_finite_path.<locals>.<genexpr>ý  s%   øé € ÐbÑRaÁJÀC ¨,¨°q¸¸Ð'>Õ?ÓRaùs   ƒc              3   ó<   <"  € T F  w  rVS R V R23x € K  	  R# 5i)Ú[Ú]Nr`   rq  s   &  €r&   r=   ru  ÿ  s'   øé € ÐfÑSeÁZÀS ¨,¨°q¸¸¸QÐ'?Õ@ÓSeùs   ƒN)
rÀ   rA   rÎ   ÚmathÚisfiniter3   ÚextendÚitemsr2   Ú	enumerate)r`  r   ÚpendingÚcurrentrt  s   &&  @r&   Ú_import_non_finite_pathÚ/SessionPortabilityMixin._import_non_finite_pathð  s”   ø€ ð �=�/ˆßØ$+§K¡K£MÑ!ˆG�\Ü˜'¤5×)Ò)´$·-²-À×2HÒ2HØ#Ð#Ü˜'¤4×(Ò(Ø—‘ÔbÐRY×R_ÑR_ÔRaÓbÖbÜ˜G¤T×*Ô*Ø—‘ÔfÔS\Ð]dÔSeÓfÖfÙr(   c                ó,   <€ V ^8„  d   QhRS[ RS[ RS[/# rm  )r$   r   )r%   r«   s   "€r&   r'   r¬     s"   ø€ ÷ ñ ¡cð ±ð ¹ñ r(   c                óx   € \         P                  ! V4      pV P                  W24      pVe   \        RV 24      hV# )a|  ``json.loads`` that refuses NaN/Infinity anywhere in the decoded value.

A JSON exponent like ``1e309`` decodes to ``float("inf")``, which strict
serializers reject and cost analytics mis-handle. Callers that intentionally
decode a JSON-backed column (model_config, reasoning items) re-check through
here so non-finite values can't reappear after the outer payload was inspected.
únon-finite number at )r›   Úloadsr€  r¤   )r³   r`  r   ÚparsedÚ
non_finites   &&&  r&   Ú_import_load_jsonÚ)SessionPortabilityMixin._import_load_json  s@   € ô —’˜EÓ"ˆØ×0Ñ0°Ó>ˆ
ØÒ!ÜÐ4°Z°LÐAÓBÐBØˆr(   c                ó<   <€ V ^8„  d   QhRS[ RS[RS[S[,          /# r_  rb  )r%   r«   s   "€r&   r'   r¬     s+   ø€ ÷ Lñ L±ð L¹Cð LÁHÉSÅMñ Lr(   c                ó  € Vf   R # RV 2p\        V\        4      '       d9    V P                  W4      p\        T\        4      '       g   \        T R24      hT# \        V\        4      '       g   \        V R24      hV P                  W4      e   \        RV 24      h \        P                  ! V4      #   \        P                   d   p\        T R24      ThR p?ii ; i  \        \
        3 d   p\        T R24      ThR p?ii ; i)Nzsession.z must be valid JSONz must be a JSON objectr„  z must be JSON serializable)
rA   r$   rˆ  r›   ÚJSONDecodeErrorr¤   r3   r€  rœ   rh  )r³   r`  ra  r   r†  ri  s   &&&   r&   Ú_import_json_object_or_noneÚ3SessionPortabilityMixin._import_json_object_or_none  s  € àŠ=ÙØ˜%˜Ð!ˆÜ�eœS×!Ò!ðIØ×.Ñ.¨uÓ;�ô ˜f¤d×+Ò+Ü  E 7Ð*@Ð!AÓBÐBØˆLÜ˜%¤×&Ò&Ü ˜wÐ&<Ð=Ó>Ð>Ø×&Ñ& uÓ3Ò?ÜÐ4°T°FÐ;Ó<Ð<ð	LÜ—:’:˜eÓ$Ð$øô ×'Ñ'ô IÜ  E 7Ð*=Ð!>Ó?ÀSÐHûðIûô œ:Ð&ô 	LÜ ˜wÐ&@ÐAÓBÈÐKûð	Lús/   £B6 Â C" Â6CÃCÃCÃ"DÃ3DÄDc                ó    <€ V ^8„  d   QhRS[ /# )r   r`  ©r   )r%   r«   s   "€r&   r'   r¬   (  s   ø€ ÷ ñ ™#ñ r(   c                óR   €  V f   V# V! V 4      #   \         \        3 d    Tu # i ; i)z;``cast(value)``; *default* for None or an unparsable value.)rh  r¤   )r`  Úcastr|   s   &&&r&   Ú
_coerce_orÚ"SessionPortabilityMixin._coerce_or'  s3   € ð	Ø#šm�7Ð<±°e³Ð<øÜœ:Ð&ô 	ØŠNð	ús   ‚ ˆ �&¥&c                ó2   <€ V ^8„  d   QhRS[ RS[RS[RS[/# )r   r`  ra  r|   r#   )r   r$   rÍ   )r%   r«   s   "€r&   r'   r¬   5  s)   ø€ ÷ ñ ©3ð ±sð ÁSð ÉSñ r(   c                ó¾   € V P                  V\        V4      pVf   V# \        V\        4      '       g(   V P                  Tu;8:  d   V P
                  8:  g    V#  V# V# )zJImport an int column: SQL-int-range or *default* (never fails the import).)r“  rÍ   rA   rm   Ú_SQLITE_INT_MINÚ_SQLITE_INT_MAX)r³   r`  ra  r|   Únumbers   &&&& r&   Ú_import_int_or_boundedÚ.SessionPortabilityMixin._import_int_or_bounded4  sZ   € ð —‘ ¤s¨GÓ4ˆØŠ>ØˆNÜ�fœd×#Ò#¨C×,?Ñ,?À6Ö,`ÈS×M`ÑM`Õ,`ØˆNð -aØˆNØˆr(   c                óX   <€ V ^8„  d   QhRS[ S[S[3,          RS[RS[ S[S[3,          /# )r   ÚmessageÚmessage_indexr#   )r3   r$   r   rÍ   )r%   r«   s   "€r&   r'   r¬   >  s8   ø€ ÷ !ñ !±±c¹3°hµð !ÑPSð !ÑX\Ñ]`ÑbeÐ]eÕXfñ !r(   c                ó   € \        V4      pVP                  R4      p\        V\        4      '       d	   V'       g   \	        RV R24      h\
         F&  pV P                  VP                  V4      V4      W5&   K(  	  V P                  VP                  R4      R4      pVe1   V P                  Tu;8:  d   V P                  8:  g   M \	        R4      hWcR&   RV R2pVP                  R4      pVe   \        VR	R
7      f   \	        V R24      hV P                  VP                  R4      V4       \         Fq  pVP                  V4      p	\        V	\        4      '       d    V P                  W— RV 24       KC  V	f   KI  V P!                  W— RV 24      p
V
f   Ke  \	        RV
 24      h	  V#   \        P                   d     K�  \         d    h i ; i)zMType-check one payload message; raises ValueError naming the offending field.r7   z	messages[z!].role must be a non-empty stringÚtoken_countz-token_count is outside SQLite's integer rangezsession.messages[rx  r5   zmessages[].timestamp©ra  z-.timestamp must be a supported Unix timestampÚcontentrp  r„  )r3   r9   rA   r$   r¤   Ú_IMPORT_MESSAGE_TEXT_FIELDSrd  rj  r—  r˜  r   Ú _validate_import_message_contentÚ_IMPORT_MESSAGE_JSON_FIELDSrˆ  r›   rŒ  r€  )r�   r�  rž  Úclean_messager7   ra  r   Úmessage_pathr5   Ú
json_valuer‡  s   &&&        r&   Ú_normalize_import_messageÚ1SessionPortabilityMixin._normalize_import_message>  sË  € ä˜W›ˆØ× Ñ  Ó(ˆÜ˜$¤×$Ò$¯DÜ˜y¨¨Ð7XÐYÓZÐZß0ˆEØ#'×#<Ñ#<¸]×=NÑ=NÈuÓ=UÐW\Ó#]ˆMÓ ñ 1à×.Ñ.¨}×/@Ñ/@ÀÓ/OÐQ^Ó_ˆØÒ"¨D×,@Ñ,@ÀKÖ,gÐSW×SgÑSgÖ,gÜÐLÓMÐMØ'2�mÑ$Ø*¨=¨/¸Ð;ˆØ!×%Ñ% kÓ2ˆ	ØÒ ¤\°)ÐCYÔ%ZÒ%bÜ ˜~Ð-ZÐ[Ó\Ð\Ø×-Ñ-¨m×.?Ñ.?À	Ó.JÈLÔYß0ˆEØ&×*Ñ*¨5Ó1ˆJÜ˜*¤c×*Ò*ðØ×*Ñ*¨:¸ÀqÈÈÐ7PÖQð
 Ô'Ø!×9Ñ9¸*ÈÐVWÐX]ÐW^ÐF_Ó`�
ØÔ)Ü$Ð'<¸Z¸LÐ%IÓJÐJñ 1ð  Ðøô ×+Ñ+ô ÚÜ!ô Øðús   ÅF)Æ)GÇGÇ
Gc                ó*   <€ V ^8„  d   QhRS[ RS[RR/# )r   r¢  r§  r#   N)r   r$   )r%   r«   s   "€r&   r'   r¬   b  s(   ø€ ÷ 	oñ 	o±sð 	oÉ#ð 	oÐRVñ 	or(   c                óš  € \        V\        4      '       dJ   \        V\        4      '       g4   V P                  Tu;8:  d   V P                  8:  g   M \        V R24      h\        V\        4      '       d,   \        P                  ! V4      '       g   \        RV R24      h\        V\        \        34      '       d   \        V R24      hR# )z?Scalar message content must be bindable and later serializable.z*.content is outside SQLite's integer ranger„  z.contentz?.content must be a string, list, object, finite number, or nullN)rA   rÍ   rm   r—  r˜  r¤   rÎ   ry  rz  ÚbytesÚ	bytearray)r³   r¢  r§  s   &&&r&   r¤  Ú8SessionPortabilityMixin._validate_import_message_contenta  s£   € ô �gœs×#Ò#¬J°wÄ×,EÒ,EØ×#Ñ# wÖE°#×2EÑ2EÖEä ˜~Ð-WÐXÓYÐYÜ�gœu×%Ò%¬d¯mªm¸G×.DÒ.DÜÐ4°\°NÀ(ÐKÓLÐLÜ�g¤¤yÐ1×2Ò2Ü ˜~Ð-lÐmÓnÐnñ 3r(   c                ó<   <€ V ^8„  d   QhRS[ RS[RS[S[,          /# r_  )r   r$   r	   rÎ   )r%   r«   s   "€r&   r'   r¬   n  s&   ø€ ÷ 9ñ 9©Cð 9¹ð 9ÁÉÅñ 9r(   c                ó    € Vf   R#  \        V4      p\        P
                  ! T4      '       d   T# R#   \        \        \        3 d     R# i ; i)zäImport a float column: finite float or None (never fails the import).

A JSON exponent like ``1e309`` decodes to ``float("inf")``; persisted, it later
breaks strict JSON serialization in the session APIs. Missing stays missing.
N)rÎ   rh  r¤   ÚOverflowErrorry  rz  )r³   r`  ra  r™  s   &&& r&   Ú_import_float_or_finiteÚ/SessionPortabilityMixin._import_float_or_finitem  sP   € ð Š=Ùð	Ü˜5“\ˆFô Ÿš v×.Ò.ˆvÐ8°DÐ8øô œ:¤}Ð5ô 	Úð	ús   ˆ3 ³AÁAc          
      ó^   <€ V ^8„  d   QhRS[ S[S[3,          RS[RS[RS[ S[S[3,          /# )r   Úrawr1   r0   r#   ©r3   r$   r   r2   )r%   r«   s   "€r&   r'   r¬   |  sE   ø€ ÷ Fñ F©T±#±s°(­^ð FÉð FÑX\ð FÑaeÑfiÑknÐfnÕaoñ Fr(   c                óf  € \        V4      pW$R&   V P                  VP                  R4      R4      VR&   R.\        O F&  pV P	                  VP                  V4      V4      WE&   K(  	  VP                  R4      pVe   \        VRR7      f   \        R4      h\         FV  pVP                  V4      p\        V\        4      '       g   K,  \        P                  ! V4      '       d   KJ  \        RV 24      h	  \         Fw  pVP                  V4      p\        V\        4      '       g   K,  \        V\        4      '       d   KD  V P                  Tu;8:  d   V P                   8:  d   Ki  M \        V R24      h	  . p\#        V4       F%  w  ršVP%                  V P'                  W©4      4       K'  	  R	VR
V/# )zAType-check one payload session + its messages; raises ValueError.rH   Úmodel_configÚparent_session_idÚ
started_atr¡  z5session.started_at must be a supported Unix timestampznon-finite number at session.z" is outside SQLite's integer ranger˜   r0   )r3   r�  r9   Ú_IMPORT_SESSION_TEXT_FIELDSrd  r   r¤   Ú_IMPORT_FLOAT_COLSrA   rÎ   ry  rz  Ú_IMPORT_INT_COLSrÍ   rm   r—  r˜  r}  r3  r©  )r�   r¶  r1   r0   Úclean_sessionra  r»  r`  Úclean_messagesrž  r�  s   &&&&       r&   Ú_normalize_import_sessionÚ1SessionPortabilityMixin._normalize_import_session|  s‡  € ä˜S›	ˆØ(�dÑØ(,×(HÑ(HÈ×IZÑIZÐ[iÓIjÐlzÓ({ˆ�nÑ%Ø)ÐHÔ,GÓHˆEØ#'×#<Ñ#<¸]×=NÑ=NÈuÓ=UÐW\Ó#]ˆMÓ ñ Ià"×&Ñ& |Ó4ˆ
ØÒ!¤l°:À\Ô&RÒ&ZÜÐTÓUÐUß'ˆEØ!×%Ñ% eÓ,ˆEÜ˜%¤×'Ô'´·²¸e×0DÔ0DÜ Ð#@ÀÀÐ!HÓIÐIñ (÷ &ˆEØ!×%Ñ% eÓ,ˆEÜ˜%¤×%Ô%¬j¸Ä×.EÔ.EØ×(Ñ(¨EÖI°T×5IÑ5I×IÐIÜ  E 7Ð*LÐ!MÓNÐNñ	 &ð
 02ˆÜ&/°Ö&9Ñ"ˆMØ×!Ñ! $×"@Ñ"@ÀÓ"XÖYñ ':à˜=¨*°nÐEÐEr(   c                óL   <€ V ^8„  d   QhRS[ S[S[S[3,          ,          RS[/# ©r   r®   r#   )r2   r3   r$   r   Útuple)r%   r«   s   "€r&   r'   r¬   ”  s(   ø€ ÷ "ñ "±±d¹3Á¸8µnÕ1Eð "É%ñ "r(   c                óè  € . p. p\        4       pR^ R^ /p\        V4       Fˆ  w  rg\        V\        4      '       d3   \	        VP                  R4      ;'       g    R4      P                  4       MRp V P                  WxWE4      p	TP                  T4       TP                  RT/T	C4       KŠ  	  W#3#   \         d8   p
RTR\	        T
4      /p	T'       d   Y‰R&   TP                  T	4        Rp
?
KÌ  Rp
?
ii ; i)	zzSize/shape/type validation of the whole payload; returns ``(normalized_items,
errors)``. Every rejected entry is reported.r0   r­  rH   r*   Úindexr”   r1   N)Úsetr}  rA   r3   r$   r9   ÚstripÚ_validate_import_sessionr¤   r3  Úadd)r�   r®   rŸ   r¦   Úseen_idsÚtotalsrÇ  r¶  r1   rž   ri  s   &&         r&   r£   Ú0SessionPortabilityMixin._validate_import_payload”  sì   € ð ,.ˆ
Ø')ˆÜ ›UˆØ˜a ¨!Ð,ˆÜ# HÖ-‰JˆEÜ=GÈÌT×=RÒ=Rœ˜SŸW™W T›]×0Ð0¨bÓ1×7Ñ7Ô9ÐXZˆJðØ×4Ñ4°SÀhÓW�ð �L‰L˜Ô$Ø×Ñ˜w¨Ð6°Ð6Ö7ñ .ð Ð!Ð!øô ô Ø ¨´°S³Ð:�ßØ)3˜Ñ&Ø—‘˜dÔ#Ýûðús   Á0B/Â/C1Â:,C,Ã,C1c                ód   <€ V ^8„  d   QhRS[ RS[RS[RS[S[S[3,          RS[S[S[ 3,          /# )r   r¶  r1   rÌ  rÍ  r#   )r   r$   rÈ  r3   rÍ   )r%   r«   s   "€r&   r'   r¬   ©  sJ   ø€ ÷  ñ  ©Cð  ¹Sð  ÉCð  ÑY]Ñ^aÑcfÐ^fÕYgð  ÑlpÑqtÑvyÐqyÕlzñ  r(   c                ó@  € \        V\        4      '       g   \        R4      hV'       g   \        R4      hW#9   d   \        R4      hVP                  R4      ;'       g    . p\        V\        4      '       g   \        R4      h\        V4      V P                  8”  d   \        R4      h\        ;QJ d    R V 4       F  '       g   K   RM	  R	M! R V 4       4      '       d   \        R
4      h VP                  4        UUu/ uF  w  rgVR8w  g   K  WgbK  	  ppp\        \        P                  ! VR	RR7      P                  R4      4      p	Y�P                  8”  d   \        R4      hTR;;,          T	,          uu&   TR,          T P                  8”  d   \        R4      hT P                  YT4      p
TR;;,          \        T
R,          4      ,          uu&   TR,          T P                   8”  d   \        R4      hT
# u uppi   \        \        3 d    \        R4      Rhi ; i)z One payload session -> normalized item; ValueError(message) on rejection. *totals*
accumulate before their limit check (a rejected oversize entry still counts).zsession must be an objectzsession id is requiredzduplicate session idr0   zmessages must be a listz-messages exceeds the per-session import limitc              3   óL   "  € T F  p\        V\        4      '       * x € K  	  R # 5ir‹   )rA   r3   r:   s   & r&   r=   ÚCSessionPortabilityMixin._validate_import_session.<locals>.<genexpr>·  s   é € Ð=±H¨S”:˜c¤4Ó(×(Ñ(³Hùs   ‚"$TFz"messages must contain only objectsr  )Úensure_asciiÚ
separatorszutf-8z!session must be JSON serializableNz%session exceeds the import size limitr­  z#import exceeds the total size limitz'messages exceeds the total import limit)rú   Ú:)rA   r3   r¤   r9   r2   rB   Ú _IMPORT_MAX_MESSAGES_PER_SESSIONÚanyr|  r›   rœ   Úencoderh  Ú_IMPORT_MAX_SESSION_BYTESÚ_IMPORT_MAX_TOTAL_BYTESrÁ  Ú_IMPORT_MAX_TOTAL_MESSAGES)r�   r¶  r1   rÌ  rÍ  r0   ÚkÚvÚmeasuredÚsession_bytesrž   s   &&&&&      r&   rÊ  Ú0SessionPortabilityMixin._validate_import_session©  sÊ  € ô ˜#œt×$Ò$ÜÐ8Ó9Ð9ßÜÐ5Ó6Ð6ØÔ!ÜÐ3Ó4Ð4Ø—7‘7˜:Ó&×,Ð,¨"ˆÜ˜(¤D×)Ò)ÜÐ6Ó7Ð7Üˆx‹=˜4×@Ñ@Ô@ÜÐLÓMÐMß‹3Ñ=±HÓ=�3�3Š3Ñ=±HÓ=×=Ò=ÜÐAÓBÐBð	Lð *-¯©¬ÔG©¡ ¸¸Y¹œ˜š©ˆHÑGÜ¤§
¢
¨8À%ÐT^Ô _× fÑ fÐgnÓ oÓpˆMð ×9Ñ9Ô9ÜÐDÓEÐEØˆw�˜=Õ(‹Ø�'�?˜T×9Ñ9Ô9ÜÐBÓCÐCØ×-Ñ-¨c¸xÓHˆØˆz×œc $ zÕ"2Ó3Õ3ÓØ�*Õ × ?Ñ ?Ô?ÜÐFÓGÐGØˆùó Høäœ:Ð&ô 	LÜÐ@ÓAÀtÐKð	Lús$   Ã-G? Ä G9ÄG9Ä4G? Ç9G? Ç?Hc                ól   <€ V ^8„  d   QhRS[ S[S[3,          RS[S[ S[S[3,          ,          RS[RR/# )r   r¶  r0   r1   r#   Nr·  )r%   r«   s   "€r&   r'   r¬   Ë  sC   ø€ ÷ %#ñ %#©T±#±s°(­^ð %#ÁtÉDÑQTÑVYÐQYÍNÕG[ð %#Ñilð %#Ðquñ %#r(   c                óè  € \        VP                  R4      VRR7      pRTR\        VP                  R4      ;'       g    R4      RV P                  WP                  R4      4      RVf   \        P                  ! 4       MT/\
         Uu/ uF3  qfV P                  VP                  V4      \        ^ 4      '       d   ^M^ bK5  	  upC\         Uu/ uF  qfVP                  V4      bK  	  upC\         Uu/ uF$  qfV P                  VP                  V4      V4      bK&  	  upC\         Uu/ uF%  qfV P                  VP                  V4      V^ 4      bK'  	  upCpVR	;;,          VR
,          ,          uu&   VP                  \        V4       R R lpV U	U
u. uF2  p	/ V	C\         U
u/ uF  qªV! V	P                  V
4      4      bK  	  up
CNK4  	  pp	p
. p. pV FB  p	V P                  V	P                  R4      \        ^4      '       d   TMTP!                  V	4       KD  	  V P#                  WVRR7       V'       dZ   TP%                  RV U	u. uF<  p	V P                  V	P                  R4      \        ^ 4      '       d   ^M^ V	R,          3NK>  	  up	4       V P'                  WV4       VP                  R\)        V4      \+        R V 4       4      V34       R# u upi u upi u upi u upi u up
i u up
p	i u up	i )zDINSERT one normalized session + its messages; counts fixed up after.r»  )r1   ra  rH   rT   ÚimportÚsystem_prompt_hashÚsystem_promptNÚauto_archivedÚarchivedc                ó0   € V ^8„  d   QhR\         R\         /# )r   r`  r#   r�  )r%   s   "r&   r'   ÚASessionPortabilityMixin._import_session_row.<locals>.__annotate__Ù  s   € ÷ 	^ñ 	^œsð 	^¤sñ 	^r(   c                 óJ   € \        V \        4      '       d   \        W R 7      # T # )r{   )rA   r$   r   )r`  s   &r&   Ú_json_valueÚ@SessionPortabilityMixin._import_session_row.<locals>._json_valueÙ  s   € Ü<FÀuÌc×<RÒ<R”? 5Ô8Ð]ÐX]Ð]r(   ÚactiveF)Úprune_checkpointsz:UPDATE messages SET active = 0, compacted = ? WHERE id = ?Ú	compactedÚ_row_idzGUPDATE sessions SET message_count = ?, tool_call_count = ? WHERE id = ?c              3   óh   "  € T F(  p\        \        VP                  R 4      4      4      x € K*  	  R# 5irE   )r   r   r9   r:   s   & r&   r=   Ú>SessionPortabilityMixin._import_session_row.<locals>.<genexpr>ï  s,   é € Ð$qÑlpÐehÔ%6Ô7HÈÏÉÐQ]ÓI^Ó7_×%`Ð%`Ólpùs   ‚02)r   r9   r$   Ú_store_system_promptÚtimeÚ_IMPORT_FLAG_COLSr“  rÍ   Ú_IMPORT_PASSTHROUGH_COLSr½  r³  r¾  rš  r€   Ú_IMPORT_SESSION_INSERT_SQLr¥  r3  Ú_insert_message_rowsÚexecutemanyÚ_prune_shadowed_checkpointsrB   rh   )r�   r‚   r¶  r0   r1   r»  ÚcolrÆ   rë  r<   rr  Úsanitized_messagesÚliverç  s   &&&&&         r&   rš   Ú+SessionPortabilityMixin._import_session_rowË  sÄ  € ä! #§'¡'¨,Ó"7ÀJÐVbÔcˆ
à�*˜h¬¨C¯G©G°HÓ,=×,IÐ,IÀÓ(JØ  $×";Ñ";¸DÇ'Á'È/ÓBZÓ"[Ø¨Ò);œ$Ÿ)š)œ+Àð
õ RcÓcÑQbÈ#˜Ÿ™¨¯©°«´s¸A×>Ò>‘AÀAÒEÑQbÑcð	
õ
 -EÓEÑ,D S�C—G‘G˜C“LÒ Ñ,DÑEð
õ PbÓbÑOaÈ�D×0Ñ0°·±¸³¸sÓCÒCÑOaÑbð
õ RbÓbÑQaÈ#�D×/Ñ/°·±¸³¸cÀ1ÓEÒEÑQaÑbð
ˆð 	ˆ× 6¨*Õ#5Õ5ÓØ�‰Ô/°Ô8õ	^ñ ksô
ÙjrÐcfÐ^ˆsÐ^ÕA\Ó]ÑA\¸#™K¨¯©°«Ó5Ò5ÑA\Ñ]Ó^Ñjrð 	ñ 
ð &(ˆØ)+ˆÛ%ˆCØ—_‘_ S§W¡W¨XÓ%6¼¸Q×?Ò?‰TÀX×UÑUÐVYÖZñ &à×!Ñ! $Ð4FÐZ_Ð!Ô`ßØ×ÑÐYá)1ó3Ù)1 #ð %)§O¡O°C·G±G¸KÓ4HÌ#Èq×$QÒ$Q™qÐWXÐZ]Ð^gÕZhÓiÙ)1ñ3ô4ð
 	×(Ñ(¨¸4Ô@à�‰Ð^Ü˜$“i¤Ñ$qÑlpÓ$qÓ!qØ ð"ö	#ùò9 dùÚEùÚbùÚbùò ^ùó
ùò3s<   Â9KÃKÃ1*KÄ&+KÆK)Æ" K$ÇK)É0K/
É6K/
Ë$K)c                ó6   <€ V ^8„  d   QhRS[ S[,          RS[/# )r   Úparent_updatesr#   )r2   rÅ  rÍ   )r%   r«   s   "€r&   r'   r¬   ó  s   ø€ ÷  ñ  ±T¹%µ[ð  ÁSñ  r(   c                ó  a a€ \        V4      oR V V3R llp^ pV Fl  w  rES P                  RV34      P                  4       pV'       d$   V! WE4      '       g   S P                  RWT34       KQ  SP                  VR4       V^,          pKn  	  V# )zðRe-attach imported children whose parent exists (in the store or the same payload)
without creating a cycle; returns the detached count. Only the closing edge of a
cycle is dropped, so later entries can still attach to the now-root session.c                ó<   € V ^8„  d   QhR\         R\         R\        /# )r   r1   Ú	parent_idr#   )r$   rm   )r%   s   "r&   r'   ÚDSessionPortabilityMixin._attach_import_parents.<locals>.__annotate__ù  s!   € ÷ 	ñ 	¬Cð 	¼Cð 	ÄDñ 	r(   c                 óÜ   <€ V 0pTpV'       d^   W29   d   R # VP                  V4       VS9   d   SV,          pK3  SP                  RV34      P                  4       pVf   R# VR,          pKe  R# )Tz;SELECT parent_session_id FROM sessions WHERE id = ? LIMIT 1Frº  )rË  r€   r™   )r1   r  Úseenr  r…   r‚   Úparent_by_childs   &&   €€r&   Ú_would_create_cycleÚKSessionPortabilityMixin._attach_import_parents.<locals>._would_create_cycleù  st   ø€ Ø�<ˆDØˆGßØ”?ÙØ—‘˜Ô!Ø˜oÔ-Ø-¨gÕ6�GÙØ—l‘lØQÐT[ÐS]óç‘(“*ð ð ’;Ù ØÐ1Õ2’Ùr(   ú+SELECT 1 FROM sessions WHERE id = ? LIMIT 1z6UPDATE sessions SET parent_session_id = ? WHERE id = ?N)r3   r€   r™   rÀ   )r‚   r   r  Údetachedr1   r  Úparent_existsr  s   f&     @r&   Ú_attach_import_parentsÚ.SessionPortabilityMixin._attach_import_parentsò  sŒ   ù€ ô
 ˜~Ó.ˆ÷	ñ 	ð$ ˆÛ%3Ñ!ˆJØ ŸL™LÐ)VÐYbÐXdÓe×nÑnÓpˆMßÑ%8¸×%OÒ%OØ—‘ÐUÐXaÐWnÖoà×#Ñ# J°Ô5Ø˜A•’ñ &4ð ˆr(   c                ób   <€ V ^8„  d   QhRS[ S[S[S[3,          ,          RS[S[S[3,          /# rÄ  )r2   r3   r$   r   )r%   r«   s   "€r&   r'   r¬     s0   ø€ ÷ 3(ñ 3(©©T±#±s°(­^Õ(<ð 3(ÁÁcÉ3ÀhÅñ 3(r(   c           
     ó.  a a€ \        V\        4      '       g   \        R4      h\        V4      S P                  8”  d   \        RS P                   R24      hS P                  V4      w  opV'       d   RRR^ R^ R^ R	V/# VV 3R
 lpS P                  V4      # )uµ  Import sessions exported by :meth:`export_session` or ``export_all``. Existing ids
are skipped. A child keeps its parent only when the parent exists or is in the
same payload; otherwise it is detached so partial imports pass FK validation.
Gateway routing, handoff, rewind and other live runtime state are reset: this
restores history, not ownership of a live channel or process. Export INCLUDES
``last_activity_*`` but import RESETS them to NULL â€” resurrecting a stale
"working ..." label would fabricate activity the watchdog acts on (pinned).

Activity contract (#76354 review S4): export INCLUDES the live activity fields (``last_activity_at``
/ ``last_activity_description`` / ``last_activity_provenance``) because they are part of the durable
row, but import deliberately RESETS them to NULL. This asymmetry is intentional and covered by
regression
(tests/gateway/test_watchdog_review.py::test_s4_export_includes_activity_import_resets_it).
zsessions must be a listzsessions must contain at most z entriesr?  Fr†   rC  r  r¦   c                 ó¨  <€ ^ RI Hp S Uu. uF<  p\        VR,          P                  R4      ;'       g    R4      P	                  4       NK>  	  ppV Uu. uF  qA! W4      '       g   K  VNK  	  up;p'       d!   RRR^ R^ R	^ R
V Uu. uF	  pRV R2NK  	  up/# . p. p. pS Fï  pVR,          p	\        V	P                  R4      ;'       g    R4      P	                  4       p
V P                  RV
34      P                  4       '       d   VP                  V
4       Kx  SP                  W	VR,          V
4       \        V	P                  R4      ;'       g    R4      P	                  4       pV'       d   VP                  W«34       VP                  V
4       Kñ  	  RRR\        V4      R\        V4      R	SP                  W4      RVRVR
. /# u upi u upi u upi )é    )Ú
retired_inr˜   rH   r*   r?  Fr†   rC  r  r¦   rB  z4 was deleted here; a deleted session is not restoredr
  r0   rº  TÚimported_idsÚskipped_ids)Ú hermes_state_mutation_retirementr  r$   r9   rÉ  r€   r™   r3  rš   rB   r  )r‚   r  rž   r  r  Údeletedr  r  r   r¶  r1   r  rŸ   r�   s   &           €€r&   r¡   Ú4SessionPortabilityMixin.import_sessions.<locals>._do,  sÐ  ø€ ÝCñ MWÓWÉJÀD”3�t˜I•×*Ñ*¨4Ó0×6Ð6°BÓ7×=Ñ=Ö?ÉJˆCÐWÙ*-ÓG©# 3°¸D×1FŸ3˜3©#ÑGÐGˆwÖGØ˜e Z°°I¸qÀ*ÈaÐQYÙdkó\mÙdkÐ]`�h˜s˜eÐ#WÓXÑdkñ\mð nð nà&(ˆLØ%'ˆKØ46ˆNÛ"�Ø˜9•o�Ü  §¡¨£×!4Ð!4°"Ó5×;Ñ;Ó=�
Ø—<‘<Ð MÐPZÈ}Ó]×fÑf×hÒhØ×&Ñ& zÔ2ÙØ×(Ñ(¨°D¸Õ4DÀjÔQÜ §¡Ð(;Ó <× BÐ BÀÓC×IÑIÓK�	ßØ"×)Ñ)¨:Ð*AÔBØ×#Ñ# JÖ/ñ #ð �d˜J¬¨LÓ(9¸9ÄcÈ+ÓFVØ˜D×7Ñ7¸ÓMØ ¨m¸[È(ÐTVðð ùò% XùÚGùò\ms   Œ(GµGÁG
Á(G
ÂG)rA   r2   r¤   rB   Ú_IMPORT_MAX_SESSIONSr£   r¥   )r�   r®   r¦   r¡   rŸ   s   f&  @r&   rI  Ú'SessionPortabilityMixin.import_sessions  s™   ù€ ô ˜(¤D×)Ò)ÜÐ6Ó7Ð7Üˆx‹=˜4×4Ñ4Ô4ÜÐ=¸d×>WÑ>WÐ=XÐX`ÐaÓbÐbØ!×:Ñ:¸8ÓDÑˆ
�FßØ˜% ¨Q°	¸1¸jÈ!ÈXÐW]Ð^Ð^ö	ð8 ×"Ñ" 3Ó'Ð'r(   r`   )r`   )F)é   r  )éÈ   )FF)NFFlûÿÿÿ         l   ÿÿÿÿ ).Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ústaticmethodrˆ   rŽ   r§   Úclassmethodr¹   rÁ   rÇ   rÐ   rã   rí   rõ   Úget_session_rich_rowrô   r  r  r  r(  r8  rP  rE  rd  rj  r€  rˆ  r�  r“  r—  r˜  rš  r©  r¤  r³  rÁ  r£   rÊ  rš   r  rI  Ú__static_attributes__Ú__classdictcell__)r«   s   @r&   rx   rx       s  ø‡ € ÙFàñó ðòCò(ð< ÷-ó ð-ð ÷ó ð÷8ò 8÷
ò ÷Pò P÷2Uð U÷"jò jð 1Ð÷Vò V÷,+ò +÷,fò f÷
fò f÷
ò 
÷"yò yð63NÐae÷ 3Nò 3N÷jð ð: ÷6ó ð6ð
 ÷Eó ðEð ÷ó ðð" ÷ó ðð ÷Ló ðLð* ÷ó ðð !€OØ#€Oà÷ó ð÷!ð !ðF ÷	oó ð	oð ÷9ó ð9÷Fð F÷0"ð "÷* ð  ÷D%#ð %#ðN ÷ ó ð ÷D3(ö 3(r(   rx   )rT   Úuser_idÚmodelrå  Ú
end_reasonr“   Ú
git_branchÚgit_repo_rootÚbilling_providerÚbilling_base_urlÚbilling_modeÚcost_statusÚcost_sourceÚpricing_versionr’   )Útool_call_idÚ	tool_nameÚeffect_dispositionÚfinish_reasonÚ	reasoningÚreasoning_contentÚplatform_message_idÚ
message_id)Úreasoning_detailsÚcodex_reasoning_itemsÚcodex_message_itemsÚabsorbed_message_uidsÚtool_call_uids)r'  r(  r¹  r)  r“   r*  r+  r,  r-  r.  r/  r0  r1  r’   )Úinput_tokensÚoutput_tokensÚcache_read_tokensÚcache_write_tokensÚreasoning_tokensÚapi_call_count)Úended_atÚestimated_cost_usdÚactual_cost_usd)rç  ræ  ÚpinnedÚhidden)r*   r*   r‹   )=r!  Úloggingr›   ry  rô  Úcollectionsr   r   r   r   Útypingr   r   r   r	   Úagent.skill_commandsr
   r   Úutilsr   Úhermes_cli.timefmtr   Úhermes_state_idsr   Úhermes_state_keysr   r   r   r   r   r   Úhermes_state_localr   Úhermes_state_commonr   r   r   r   Úhermes_state_messagesr   r   ri   Ú	getLoggerrG  r¼  r£  r¥  r÷  rö  r¾  r½  rõ  r.   rá   rê   rB   Ú_CRON_ADMISSION_SQLrà   rß   rv   rx   r`   r(   r&   Ú<module>rW     sM  ðñó Û Û Û Ý ß ,Ñ ,ß ,Ó ,ç UÝ !Ý +Ý +÷÷ õ -ß fÓ fß FÛ ð 
×	Ò	˜>Ó	*€ðÐ ð
Ð ðÐ ðÐ ð.Ð ðÐ ð KÐ àEÐ ÷ð YÐ ð%à%2 OÐ3KðMð ð
 Ð(Ð)ð *'Ù'*Ð+>Ó'?À!Õ'CÐ&DÐDdÑehÐi|Óe}Ðd~ðØÐ
  ð-ð ðIàI\ÐH]ð_ð ð
+Ø+>Ð*?¸yðJð ÷
%÷Ph
(ó h
(r(   