
    `gj+              
      ~   d Z ddlmZ ddlZddlZddlmZmZ ddlmZm	Z	 ddl
mZ ddlmZmZ ddlmZ e G d	 d
             ZddZddZd dZd!dZd"dZd#dZd$dZd%dZd&dZd'dZd(dZd)dZd*dZd+dZd,dZ d-dZ!e"dk(  r5 e e              Z# e$ ejJ                   ee# ee#            d             yy).a0  Assemble the "learning made visible" graph for desktop.

This graph is intentionally scoped to what a user actually learns over time:
- non-base, learned/profile skills (agent-created or used),
- memory chunks from ``MEMORY.md`` / ``USER.md`` as first-class nodes.

Skill links come from declared ``related_skills``. Memory-to-skill links are
derived from lexical overlap so the graph can answer "which learned skills are
connected to the things I remember?".

Run as a module to print edge-density stats against real data:

    python -m agent.learning_graph
    )annotationsN)	dataclassfield)datetimetimezone)Path)AnyOptional)get_hermes_homec                      e Zd ZU ded<   ded<   dZded<   dZded<   d	Zd
ed<   dZded<   dZded<   dZ	ded<    e
e      Zded<   y)	SkillNodestrnamecategoryprofilesourceNOptional[int]	timestampr   int	use_countactivestatezOptional[str]
created_byFboolpinned)default_factory	list[str]related)__name__
__module____qualname____annotations__r   r   r   r   r   r   r   listr        G/root/.hermes/venv/lib/python3.12/site-packages/agent/learning_graph.pyr   r      sW    
IMFC#I}#IsE3 $J$FDt4GY4r%   r   c                T    	 ddl m}  ||       \  }}|xs i S # t        $ r i cY S w xY w)Nr   )parse_frontmatter)agent.skill_utilsr(   	Exception)textr(   fm_s       r&   _frontmatterr.   )   s5    7!$'AxR 	s    ''c                    | j                  d      }t        |t              r|j                  d      nd}t        |t              r|S i S )z``metadata.hermes`` as a dict, tolerant of the string-valued frontmatter
    that ``parse_frontmatter``'s malformed-YAML fallback produces.metadatahermesN)get
isinstancedict)r,   metar1   s      r&   _hermes_metar6   3   s?     66*D#-dD#9TXXhtF-6525r%   c                   | j                  d      xs t        |       j                  d      }t        |t              rA|D cg c]5  }t	        |      j                         st	        |      j                         7 c}S t        |t              rM|j                  d      j                  d      D cg c]#  }|j                         s|j                         % c}S g S c c}w c c}w )Nrelated_skillsz[],)r2   r6   r3   r#   r   stripsplit)r,   rawrs      r&   _relatedr>   ;   s    
&&!
"
Ll2&6&:&:;K&LC#t(+>1s1v||~A>>#s#&99T?#8#8#=Ka	KKI ?Ks   C!C1C#C#c                    | j                  d      xs t        |       j                  d      }|rt        |      S |j                  }t	        |      dk\  r|d   S dS )Nr      general)r2   r6   r   partslen)r,   skill_mdcatrC   s       r&   	_categoryrG   D   sS    
&&

@R 0 4 4Z @C
3xNNEE
a596Y6r%   c              #  z   K   | D ]2  \  }}|j                         s|j                  d      D ]  }||f 
 4 y w)NzSKILL.md)existsrglob)rootsr   rootpaths       r&   _iter_skill_filesrN   M   sD      #;;=

:. #dl"##s   ;;c                     	 ddl m}   |        S # t        $ rL t               dz  dz  }	 t	        j
                  |j                  d            cY S # t        $ r i cY cY S w xY ww xY w)Nr   )
load_usageskillsz.usage.jsonutf-8encoding)tools.skill_usagerP   r*   r   jsonloads	read_text)rP   rM   s     r&   _load_usagerY   T   sf    	0|  8+m;	::dnngn>?? 	I		s,    A$$AA$A A$A  A$c                   	 | y t        | t        t        f      rt        |       S t        |       j	                         }|sy 	 t        t        |            S # t
        $ rm t        j                  |j                  dd            }|j                   |j                  t        j                        }t        |j                               cY S w xY w# t        $ r Y y w xY w)NZz+00:00)tzinfo)r3   r   floatr   r:   
ValueErrorr   fromisoformatreplacer\   r   utcr   r*   )valuesparseds      r&   
_to_int_tsre   a   s    =ec5\*u:J	+uQx=  	+++AIIc8,DEF}}$x||<v'')**		+
  s:   C  C C A A3C
C CC 	CCc                R    dD ]"  }t        | j                  |            }| |c S  y )N)last_activity_atlast_used_atlast_viewed_atlast_patched_at
created_at)re   r2   )reckeytss      r&   _usage_timestampro   u   s2    f %>I r%   c                   t               }i }t        |       D ]Y  \  }}t        d |j                  D              r$	 t	        |j                  d      d d       }t        |j                  d      xs |j                  j                        j                         }|r||v r|j                  |i       }t        |      }t        |j                         j                        }	t!        |t#        ||      ||xs |	t%        |j                  dd      xs d      t        |j                  dd	      xs d	      |j                  d
      t'        |j                  dd            t)        |      	      ||<   \ |S # t        $ r Y kw xY w)Nc              3  $   K   | ]  }|d v  
 yw)>   .git.hub.archivenode_modulesNr$   ).0ps     r&   	<genexpr>z$build_skill_nodes.<locals>.<genexpr>   s     YQq@@Ys   rR   rS   i  r   r   r   r   r   r   r   F)	r   r   r   r   r   r   r   r   r   )rY   rN   anyrC   r.   rX   OSErrorr   r2   parentr   r:   ro   re   statst_mtimer   rG   r   r   r>   )
skill_rootsusagenodesr   rE   r,   r   rl   last_activityfile_tss
             r&   build_skill_nodesr   }   s_   ME"$E-k: 
Y(..YY	h00'0B5DIJB 266&>9X__%9%9:@@Btu}iib!(-X]]_556r8,#.w#''+q16Q7cgggx0<H=ww|,%01RL

d
0 L'  		s   E77	FFc                   t               }g }| j                         D ]m  }|j                  D ]\  }|| v s||j                  k7  st	        |j                  |f      \  }}||f}||vs;|j                  |       |j                  |       ^ o |S )zEUndirected related_skills edges where BOTH endpoints exist (deduped).)setvaluesr   r   sortedaddappend)r   seenedgesnodetargetabrm   s           r&   build_edgesr      s    !$D#%E &ll 	&F6TYY#6tyy&121!fd?HHSMLL%	&& Lr%   c                   t               }|D ]'  \  }}|j                  |       |j                  |       ) i }| j                         D ].  }|j                  |j                  d      dz   ||j                  <   0 t        |       xs d}t        |       t        |      t        t        |      |z  d      t        |      t        d|t        |      z
  z  |z  d      t        |      t        d | j                         D              t        d | j                         D              t        |j                         d       d d	 d
	S )Nr      r@   d   c              3  @   K   | ]  }|j                   d k(  sd  yw)agentr   N)r   rv   xs     r&   rx   z density_stats.<locals>.<genexpr>   s     R1!,,':QQR   c              3  @   K   | ]  }|j                   d kD  sd  yw)r   r   N)r   r   s     r&   rx   z density_stats.<locals>.<genexpr>   s     A!qAAr   c                    | d    S Nr   r$   kvs    r&   <lambda>zdensity_stats.<locals>.<lambda>   s    r!uf r%   rm      )	r   related_edgesedges_per_nodelinked_nodesisolated_pct
categoriesagent_createdusedtop_categories)
r   r   r   r2   r   rD   roundsumr   items)r   r   linkedr   r   catsns          r&   density_statsr      s   uF 1

1

1 D\\^ 788AJJ2Q6QZZ7E
aAUUE
Q2FcQV_591=$iRRRAu||~AA 3DEbqI
 
r%   c            
     (   t               dz  } g }dD ]  \  }}| |z  }	 |j                  d      j                         }t        |j	                         j
                        }t        d |j                  d      D              D ]|  \  }}|s	|j                         d   j                         j                  d      j                         }	|j                  ||||z   nd	t        |	      d
kD  r|	d	d
 dz   n|	|d	d d       ~  |S # t        $ r Y w xY w)u   Freeform memory as readable cards.

    ``MEMORY.md`` / ``USER.md`` are prose split on bare ``§`` separators; each
    chunk becomes one card. Every chunk is surfaced — the graph shows everything.
    memories))z	MEMORY.mdmemory)zUSER.mdr   rR   rS   c              3  <   K   | ]  }|j                           y w)N)r:   )rv   cs     r&   rx   z _memory_cards.<locals>.<genexpr>   s     )R!''))Rs   u   
§
r   z# NP   u   …i  )r   r   titlebody)r   rX   r:   re   r|   r}   rz   	enumerater;   
splitlineslstripr   rD   )
basecardsfnamer   rM   r+   r   	chunk_idxchunkfirsts
             r&   _memory_cardsr      s(    z)D"$EJ ve|	>>7>399;D !5!56G !*)RTZZ=Q)R R 	Iu$$&q)//188>DDFELL$8?8K9!4QU58Z"_eCRj50%!%4L			& L  		s   AD	DDc                    t        j                  d| j                               D ch c]  }t        |      dk\  s| c}S c c}w )Nz
[^a-z0-9]+r@   )rer;   lowerrD   )r+   ts     r&   	_tokenizer      s1    xxtzz|<L!A!ALLLs
   AAc                H   g }|D cg c]2  }|t        |j                        |j                  j                         f4 }}t        |       D ]  \  }}d|d    d| }|j	                  dd       d|j	                  dd       j                         }t        |      }	g }
|D ]E  \  }}}d}||v r|d	z  }|t        ||	z        z  }|dkD  s)|
j                  ||j                  f       G |
j                  d
        |
d d D ]  \  }}|j                  ||f         |S c c}w )Nmemory:r   :r    
r   r      c                    | d    | d   fS )Nr   r   r$   )r   s    r&   r   z%_memory_skill_edges.<locals>.<lambda>   s    AaD5!A$- r%   r      )r   r   r   r   r2   rD   r   sort)memory_cardsrQ   r   rc   
skill_metaidxcardmem_idr+   text_tokensscoredskilltokensskill_name_lowerscorer-   
skill_names                    r&   _memory_skill_edgesr      sG   #%EBHIQ1i'8IJI|, /	T4>*!C51((7B'(488FB+?*@AGGIo(*/9 	3+E6+E4'
S+-..Eqyuejj12	3 	/0#BQZ 	/MAzLL&*-.	// L! Js   7Dc                     t        t              j                         j                  j                  } t	               dz  }d| dz  fd|fgS )NrQ   r   r   )r   __file__resolver{   r   )repohome_skillss     r&   _skill_rootsr      sF    >!!#**11D!#h.KTH_%	;'?@@r%   c                    t        t                     } | j                         D ci c]5  \  }}|j                  dk7  r!|j                  dk(  s|j
                  dkD  r||7 }}}t        |      }t               }t        |t        |j                                     }||z   }i }|j                         D ].  }|j                  |j                  d      dz   ||j                  <   0 |rt        |      |d<   |j                         D 	cg c]^  }	|	j                  |	j                  d|	j                  |	j                  |	j
                  |	j                   |	j                  |	j"                  d	` }
}	t%        |      D ]?  \  }}|
j'                  d|d	    d
| |d   d|d	   |j                  d      dddddd
       A |
|D cg c]
  \  }}||d c}}t)        |j                         d       D 	cg c]
  \  }}	||	d c}	}|i t+        ||      t        |      t        |      t        |      ddS c c}}w c c}	w c c}}w c c}	}w )a  Full payload for the desktop learning panel.

    Focus on what is profile-learned and actionable:
    - skills that are NOT base-installed and show real learning signal
      (agent-created or used),
    - memory chunks as first-class graph nodes connected to those learned skills.
    r   r   r   r   r   r   )	idlabelkindr   r   useCountr   	createdByr   r   r   r   r   r   r   F)
r   r   r   memorySourcer   r   r   r   r   r   )r   r   c                    | d    S r   r$   r   s    r&   r   z&build_learning_graph.<locals>.<lambda>:  s    A r%   r   )r   count)memory_nodesmemory_skill_edgeslearned_skills)r   r   clustersr   stats)r   r   r   r   r   r   r   r   r   r#   r   r2   r   rD   r   r   r   r   r   r   r   r   )
all_skillsr   r   r   skill_edgesr   memory_edgesr   r   r   graph_nodesir   r   r   r   s                   r&   build_learning_graphr      se    #<>2J %**,D$;;& doo&@DNNUVDV 	d
N 
 n-K ?L&|T.:O:O:Q5RSL,&E!H%%' E"*,,t}}a"@1"DE .  &&(  &&VV

WWhh
	
K  \* 
4X/q4g  $X!XXk2$!%	

" 9>?AQ!,? x~~/5FG
1 Q'
 
NK8
-"%l"3!.1	
 ] @ @
s   :H3A#H9>H>/I
__main__   )indent)r+   r   returndict[str, Any])r,   r   r   r   )r,   r   r   r   )r,   r   rE   r   r   r   )rK   list[tuple[str, Path]])r   zdict[str, dict[str, Any]])rb   r	   r   r   )rl   r   r   r   )r~   r   r   dict[str, SkillNode])r   r   r   list[tuple[str, str]])r   r   r   r   r   r   )r   list[dict[str, Any]])r+   r   r   zset[str])r   r   rQ   zlist[SkillNode]r   r   )r   r   )r   r   )&__doc__
__future__r   rV   r   dataclassesr   r   r   r   pathlibr   typingr	   r
   hermes_constantsr   r   r.   r6   r>   rG   rN   rY   re   ro   r   r   r   r   r   r   r   r   r   r   printdumpsr$   r%   r&   <module>r     s    #  	 ( '    , 	5 	5 	567#
(>,<M*AEP zln-E	*$**]5+e*<=a
HI r%   