
    i_                     <   d Z ddlZddlZddlmZmZ ddlmZ ddlmZm	Z	m
Z
 ddlmZmZmZmZmZ eZddeded	ed
efdZ	 	 ddddddde	eef         ez  dededededed	ed
eeef         fdZded
efdZdde
e         ded
e
e         fdZ G d d          ZdS )ua  
Session Insights Engine for Hermes Agent.

Analyzes historical session data from the SQLite state database to produce
comprehensive usage insights — token consumption, cost estimates, tool usage
patterns, activity trends, model/platform breakdowns, and session metrics.

Inspired by Claude Code's /insights command, adapted for Hermes Agent's
multi-platform architecture with additional cost estimation and platform
breakdown capabilities.

Usage:
    from agent.insights import InsightsEngine
    engine = InsightsEngine(db)
    report = engine.generate(days=30)
    print(engine.format_terminal(report))
    N)Counterdefaultdict)datetime)AnyDictList)CanonicalUsageDEFAULT_PRICINGestimate_usage_costformat_duration_compacthas_known_pricing
model_nameproviderbase_urlreturnc                 &    t          | ||          S )z@Check if a model has known pricing (vs unknown/custom endpoint).r   r   )r   )r   r   r   s      3/home/piyush/.hermes/hermes-agent/agent/insights.py_has_known_pricingr   $   s    Z(XNNNN    )cache_read_tokenscache_write_tokensr   r   session_or_modelinput_tokensoutput_tokensr   r   c                   t          | t                    r| }|                    d          pd}t          |                    d          pd|                    d          pd|                    d          pd|                    d          pd          }	|                    d	          }|                    d
          }n| pd}t          ||||          }	t	          ||	||          }
t          |
j        pd          |
j        fS )z?Estimate the USD cost for a session row or a model/token tuple.model r   r   r   r   r   )r   r   r   r   billing_providerbilling_base_urlr           )
isinstancedictgetr	   r   float
amount_usdstatus)r   r   r   r   r   r   r   sessionr   usageresults              r   _estimate_costr+   )   s+    "D)) 
"G$$* ^449!++o66;!%kk*=>>C!&{{+?@@EA	
 
 
 ;;122;;122 &B%'/1	
 
 
 !	  F ")c**FM99r   secondsc                      t          |           S )z5Format seconds into a human-readable duration string.)r   )r,   s    r   _format_durationr.   P   s    "7+++r      values	max_widthc                 n    | rt          |           nddk    rd | D             S fd| D             S )z7Create simple horizontal bar chart strings from values.   r   c                     g | ]}d S )r    ).0_s     r   
<listcomp>z_bar_chart.<locals>.<listcomp>Y   s    ###q###r   c           
      l    g | ]0}|d k    r&dt          dt          |z  z                      z  nd1S )r   u   █r3   r   )maxint)r6   vr1   peaks     r   r8   z_bar_chart.<locals>.<listcomp>Z   sF    WWW1QEC3q4x)3445555BWWWr   )r:   )r0   r1   r=   s    `@r   
_bar_chartr>   U   sS     '3v;;;aDqyy##F####WWWWWPVWWWWr   c            	          e Zd ZdZd Zd dededeeef         fdZ	d	Z
d
e
 dZd
e
 dZd!dededee         fdZd!dededee         fdZd!dededee         fdZd!dededefdZdee         dedefdZdee         dee         fdZdee         dee         fdZdee         dee         fdZdee         deeef         fdZdee         defdZdee         dee         fdZdedefdZdedefdZdS )"InsightsEnginez
    Analyzes session history and produces usage insights.

    Works directly with a SessionDB instance (or raw sqlite3 connection)
    to query session and message data.
    c                 ,    || _         |j        | _        dS )z
        Initialize with a SessionDB instance.

        Args:
            db: A SessionDB instance (from hermes_state.py)
        N)db_conn)selfrB   s     r   __init__zInsightsEngine.__init__e   s     X


r      Ndayssourcer   c                 x   t          j                     |dz  z
  }|                     ||          }|                     ||          }|                     ||          }|                     ||          }|s||di g g g dddddg di g d
S |                     ||          }|                     |          }	|                     |          }
|                     |          }| 	                    |          }| 
                    |          }|                     |          }||dt          j                     ||	|
||||dS )	z
        Generate a complete insights report.

        Args:
            days: Number of days to look back (default: 30)
            source: Optional filter by source platform

        Returns:
            Dict with all computed insights
        iQ Tr   total_skill_loadstotal_skill_editstotal_skill_actionsdistinct_skills_usedsummary
top_skills)
rG   source_filteremptyoverviewmodels	platformstoolsskillsactivitytop_sessionsF)rG   rR   rS   generated_atrT   rU   rV   rW   rX   rY   rZ   )time_get_sessions_get_tool_usage_get_skill_usage_get_message_stats_compute_overview_compute_model_breakdown_compute_platform_breakdown_compute_tool_breakdown_compute_skill_breakdown_compute_activity_patterns_compute_top_sessions)rD   rG   rH   cutoffsessions
tool_usageskill_usagemessage_statsrT   rU   rV   rW   rX   rY   rZ   s                  r   generatezInsightsEngine.generateo   s    u- %%ff55))&&99
++FF;;//?? 	!' ./-./001	    #%   "%  , ))(MBB..x8844X>>	,,Z88..{;;228<<11(;; # IKK " (
 
 	
r   zid, source, model, started_at, ended_at, message_count, tool_call_count, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, billing_provider, billing_base_url, billing_mode, estimated_cost_usd, actual_cost_usd, cost_status, cost_sourcezSELECT zL FROM sessions WHERE started_at >= ? AND source = ? ORDER BY started_at DESCz= FROM sessions WHERE started_at >= ? ORDER BY started_at DESCrh   c                     |r#| j                             | j        ||f          }n!| j                             | j        |f          }d |                                D             S )z&Fetch sessions within the time window.c                 ,    g | ]}t          |          S r5   )r#   )r6   rows     r   r8   z0InsightsEngine._get_sessions.<locals>.<listcomp>   s    777cS		777r   )rC   execute_GET_SESSIONS_WITH_SOURCE_GET_SESSIONS_ALLfetchall)rD   rh   rH   cursors       r   r]   zInsightsEngine._get_sessions   sg     	KZ''(FQWHXYYFFZ''(>	JJF77V__%6%67777r   c                 r   t                      }|r| j                            d||f          }n| j                            d|f          }|                                D ]}||d         xx         |d         z  cc<   |r| j                            d||f          }n| j                            d|f          }t                      }|                                D ]}	 |d         }t	          |t
                    rt          j        |          }t	          |t                    rY|D ]V}	t	          |	t                    r|	
                    di           ni }
|

                    d	          }|r||xx         d
z  cc<   W# t          j        t          t          f$ r Y w xY w|s|r|}ns|rq|rot          |          t          |          z  }t                      }|D ]=}t          |
                    |d          |
                    |d                    ||<   >|}d |                                D             S )a  Get tool call counts from messages.

        Uses two sources:
        1. tool_name column on 'tool' role messages (set by gateway)
        2. tool_calls JSON on 'assistant' role messages (covers CLI where
           tool_name is not populated on tool responses)
        aR  SELECT m.tool_name, COUNT(*) as count
                   FROM messages m
                   JOIN sessions s ON s.id = m.session_id
                   WHERE s.started_at >= ? AND s.source = ?
                     AND m.role = 'tool' AND m.tool_name IS NOT NULL
                   GROUP BY m.tool_name
                   ORDER BY count DESCaA  SELECT m.tool_name, COUNT(*) as count
                   FROM messages m
                   JOIN sessions s ON s.id = m.session_id
                   WHERE s.started_at >= ?
                     AND m.role = 'tool' AND m.tool_name IS NOT NULL
                   GROUP BY m.tool_name
                   ORDER BY count DESC	tool_namecountzSELECT m.tool_calls
                   FROM messages m
                   JOIN sessions s ON s.id = m.session_id
                   WHERE s.started_at >= ? AND s.source = ?
                     AND m.role = 'assistant' AND m.tool_calls IS NOT NULLzSELECT m.tool_calls
                   FROM messages m
                   JOIN sessions s ON s.id = m.session_id
                   WHERE s.started_at >= ?
                     AND m.role = 'assistant' AND m.tool_calls IS NOT NULL
tool_callsfunctionnamer3   r   c                     g | ]
\  }}||d S ))rw   rx   r5   )r6   r{   rx   s      r   r8   z2InsightsEngine._get_tool_usage.<locals>.<listcomp>&  s4     
 
 
e //
 
 
r   )r   rC   rq   rt   r"   strjsonloadslistr#   r$   JSONDecodeError	TypeErrorAttributeErrorsetr:   most_common)rD   rh   rH   tool_countsru   rp   cursor2tool_calls_countscallscallfuncr{   	all_toolsmergedtools                  r   r^   zInsightsEngine._get_tool_usage   s    ii  	Z''*  	 	FF Z''* 		 	F ??$$ 	: 	:CK()))S\9))))  	j((N
   GG j((N
 	 G $II##%% 	 	CL)eS)) . Ju--EeT** 9 % 9 9;EdD;Q;QYtxx
B777WY#xx// 9-d333q8333()^D   
  
	!0 
	!+KK 	!. 	! K((3/@+A+AAIYYF! ] ]";??4#;#;=N=R=RSWYZ=[=[\\t K
 
*6688
 
 
 	
s   BE??FFc           
         i }|r| j                             d||f          }n| j                             d|f          }|                                D ]}	 |d         }t          |t                    rt          j        |          }t          |t                    sKn# t
          j        t          f$ r Y dw xY w|d         }|D ]W}t          |t                    s|                    di           }	|	                    d          }
|
dvrI|	                    d          }t          |t                    r2	 t          j        |          }n# t
          j        t          f$ r Y w xY wt          |t                    s|                    d          }t          |t                    r|                                s|                    ||d	d	d
d          }|
dk    r|dxx         dz  cc<   n|dxx         dz  cc<   ||d         ||d         k    r||d<   Yt          |                                          S )z2Extract per-skill usage from assistant tool calls.a  SELECT m.tool_calls, m.timestamp
                   FROM messages m
                   JOIN sessions s ON s.id = m.session_id
                   WHERE s.started_at >= ? AND s.source = ?
                     AND m.role = 'assistant' AND m.tool_calls IS NOT NULLzSELECT m.tool_calls, m.timestamp
                   FROM messages m
                   JOIN sessions s ON s.id = m.session_id
                   WHERE s.started_at >= ?
                     AND m.role = 'assistant' AND m.tool_calls IS NOT NULLry   	timestamprz   r{   >   
skill_viewskill_manage	argumentsr   N)skill
view_countmanage_countlast_used_atr   r   r3   r   r   )rC   rq   rt   r"   r}   r~   r   r   r   r   r#   r$   strip
setdefaultr0   )rD   rh   rH   skill_countsru   rp   r   r   r   r   rw   args
skill_nameentrys                 r   r_   zInsightsEngine._get_skill_usage+  s   24 	Z''N
   FF Z''N
 	 F ??$$ 1	6 1	6CL)eS)) . Ju--E!%.. ()4    K(I &6 &6!$-- xx
B// HHV,,	$BBBxx,,dC(( !!#z$// 0)< ! ! ! !!$-- !XXf--
!*c22 *:J:J:L:L $//!+&'()(,	   ,,,'''1,''''.)))Q.)))(.)1Y~AV5V5V,5E.)M&6P L''))***s%   ABB87B89EE'&E'c                     |r| j                             d||f          }n| j                             d|f          }|                                }|rt          |          ndddddS )z!Get aggregate message statistics.a  SELECT
                     COUNT(*) as total_messages,
                     SUM(CASE WHEN m.role = 'user' THEN 1 ELSE 0 END) as user_messages,
                     SUM(CASE WHEN m.role = 'assistant' THEN 1 ELSE 0 END) as assistant_messages,
                     SUM(CASE WHEN m.role = 'tool' THEN 1 ELSE 0 END) as tool_messages
                   FROM messages m
                   JOIN sessions s ON s.id = m.session_id
                   WHERE s.started_at >= ? AND s.source = ?a  SELECT
                     COUNT(*) as total_messages,
                     SUM(CASE WHEN m.role = 'user' THEN 1 ELSE 0 END) as user_messages,
                     SUM(CASE WHEN m.role = 'assistant' THEN 1 ELSE 0 END) as assistant_messages,
                     SUM(CASE WHEN m.role = 'tool' THEN 1 ELSE 0 END) as tool_messages
                   FROM messages m
                   JOIN sessions s ON s.id = m.session_id
                   WHERE s.started_at >= ?r   )total_messagesuser_messagesassistant_messagestool_messages)rC   rq   fetchoner#   )rD   rh   rH   ru   rp   s        r   r`   z!InsightsEngine._get_message_statsw  s     	Z''?  
 
FF Z''. 	
 
F oo 
tCyyy!"#a&
 &
 	
r   ri   rl   c                 r   t          d |D                       }t          d |D                       }t          d |D                       }t          d |D                       }||z   |z   |z   }t          d |D                       }t          d |D                       }	d}
d}t                      }t                      }d}d}|D ]}|                    d	          pd
}t          |          \  }}|
|z  }
||                    d          pdz  }d|v r|                    d          d         n|pd}|dk    r|dz  }n|dk    r|dz  }t          ||                    d          |                    d                    r|                    |           |                    |           g }|D ]N}|                    d          }|                    d          }|r |r||k    r|                    ||z
             O|rt          |          dz  nd}|rt          |          t          |          z  nd}d |D             }|rt          |          nd}|rt          |          nd}i dt          |          d|	d|d|d|d|d|d|d |
d!|d"|d#|d$|r|	t          |          z  ndd%|r|t          |          z  ndd&|                    d&          pdd'|                    d'          pdd(|                    d(          pd||t          |          t          |          ||d)S )*z'Compute high-level overview statistics.c              3   D   K   | ]}|                     d           pdV  dS )r   r   Nr$   r6   ss     r   	<genexpr>z3InsightsEngine._compute_overview.<locals>.<genexpr>  s3      GG!%%//41GGGGGGr   c              3   D   K   | ]}|                     d           pdV  dS )r   r   Nr   r   s     r   r   z3InsightsEngine._compute_overview.<locals>.<genexpr>  s3      II1155116QIIIIIIr   c              3   D   K   | ]}|                     d           pdV  dS )r   r   Nr   r   s     r   r   z3InsightsEngine._compute_overview.<locals>.<genexpr>  s4      QQ1quu%899>QQQQQQQr   c              3   D   K   | ]}|                     d           pdV  dS )r   r   Nr   r   s     r   r   z3InsightsEngine._compute_overview.<locals>.<genexpr>  s4      SSQ&: ; ; @qSSSSSSr   c              3   D   K   | ]}|                     d           pdV  dS )tool_call_countr   Nr   r   s     r   r   z3InsightsEngine._compute_overview.<locals>.<genexpr>  s4      OOquu%677<1OOOOOOr   c              3   D   K   | ]}|                     d           pdV  dS )message_countr   Nr   r   s     r   r   z3InsightsEngine._compute_overview.<locals>.<genexpr>  s3      KKQQUU?338qKKKKKKr   r!   r   r   r   actual_cost_usd/unknownincludedr3   r   r    
started_atended_at  c                 H    g | ]}|                     d           |d           S )r   r   r   s     r   r8   z4InsightsEngine._compute_overview.<locals>.<listcomp>  s-    WWW!155CVCVWaoWWWr   Ntotal_sessionsr   total_tool_callstotal_input_tokenstotal_output_tokenstotal_cache_read_tokenstotal_cache_write_tokenstotal_tokensestimated_costactual_costtotal_hoursavg_session_durationavg_messages_per_sessionavg_tokens_per_sessionr   r   r   )date_range_startdate_range_endmodels_with_pricingmodels_without_pricingunknown_cost_sessionsincluded_cost_sessions)sumr   r$   r+   splitr   addappendlenminr:   sorted)rD   ri   rl   total_inputtotal_outputtotal_cache_readtotal_cache_writer   r   r   
total_costr   r   r   r   r   r   r   	estimatedr'   display	durationsstartendr   avg_durationstarted_timestampsr   r   s                                r   ra   z InsightsEngine._compute_overview  s]   GGhGGGGGIIIIIIIQQQQQQQSS(SSSSS"\14DDGXXOOhOOOOOKK(KKKKK 
!ee!$ !!" 	4 	4AEE'NN(bE .q 1 1Iv)#J155!233:s:K.1Ullekk#&&r**AS)G##&!+&&9$$%*%!%/A)B)BAEEJ\D]D]^^ 4#''0000&**73333 	 	. 	.AEE,''E%%
##C . .u  u---/8?c)nnt++a:CJs9~~I66 XWxWWW6HR31222d4FP/000D
c(mm
n
  0
 !+	

 "<
 &'7
 '(9
 L
 j
 ;
 ;
 #L
 '((YX(F(FXY
 %h&UlS]]&B&BTU
 ]..??D1
  !-"3"34H"I"I"NQ!
" ]..??D1#
$ !1,#)*=#>#>&,-C&D&D%:&</
 
 
 	
r   c                    t          d           }|D ]}|                    d          pd}d|v r|                    d          d         n|}||         }|dxx         dz  cc<   |                    d          pd	}|                    d
          pd	}|                    d          pd	}	|                    d          pd	}
|dxx         |z  cc<   |d
xx         |z  cc<   |dxx         |	z  cc<   |dxx         |
z  cc<   |dxx         ||z   |	z   |
z   z  cc<   |dxx         |                    d          pd	z  cc<   t          |          \  }}|dxx         |z  cc<   t	          ||                    d          |                    d                    |d<   ||d<   d |                                D             }|                    d d           |S )zBreak down usage by model.c            	          dddddddddS )Nr   r!   )ri   r   r   r   r   r   ry   costr5   r5   r   r   <lambda>z9InsightsEngine._compute_model_breakdown.<locals>.<lambda>  s!    1q!"!Q*
 *
 r   r   r   r   r   ri   r3   r   r   r   r   r   r   ry   r   r   r   r    has_pricingcost_statusc                      g | ]\  }}d |i|S )r   r5   )r6   r   datas      r   r8   z;InsightsEngine._compute_model_breakdown.<locals>.<listcomp>  s6     
 
 
t e$t$
 
 
r   c                 "    | d         | d         fS )Nr   ri   r5   xs    r   r   z9InsightsEngine._compute_model_breakdown.<locals>.<lambda>  s    1^#4a
m"D r   Tkeyreverse)r   r$   r   r+   r   itemssort)rD   ri   
model_datar   r   display_modeldinpout
cache_readcache_writeestimater'   r*   s                 r   rb   z'InsightsEngine._compute_model_breakdown  sT     "
 "
  
  	& 	&AEE'NN/iE475LLEKK,,R00eM=)AjMMMQMMM%%'',1C%%((-AC2338qJ%% 455:Kn$o#%!"""j0""""###{2###nsZ!7+!EElOOOquu%677<1<OOO-a00HffIII!III1%?Q9R9RTUTYTYZlTmTmnnAm%Am
 
)//11
 
 

 	DDdSSSr   c                    t          d           }|D ]1}|                    d          pd}||         }|dxx         dz  cc<   |dxx         |                    d          pdz  cc<   |                    d	          pd}|                    d
          pd}|                    d          pd}|                    d          pd}	|d	xx         |z  cc<   |d
xx         |z  cc<   |dxx         |z  cc<   |dxx         |	z  cc<   |dxx         ||z   |z   |	z   z  cc<   |dxx         |                    d          pdz  cc<   3d |                                D             }
|
                    d d           |
S )z$Break down usage by platform/source.c            	          dddddddddS )Nr   )ri   messagesr   r   r   r   r   ry   r5   r5   r   r   r   z<InsightsEngine._compute_platform_breakdown.<locals>.<lambda>  s!    q!Q"#Qa-
 -
 r   rH   r   ri   r3   r   r   r   r   r   r   r   r   ry   r   c                      g | ]\  }}d |i|S )platformr5   )r6   r   r   s      r   r8   z>InsightsEngine._compute_platform_breakdown.<locals>.<listcomp>"  s6     
 
 
$ *T*
 
 
r   c                     | d         S )Nri   r5   r   s    r   r   z<InsightsEngine._compute_platform_breakdown.<locals>.<lambda>&  s
    !J- r   Tr   )r   r$   r   r   )rD   ri   platform_datar   rH   r   r   r   r   r   r*   s              r   rc   z*InsightsEngine._compute_platform_breakdown
  s   # %
 %
    	= 	=AUU8__1	Ff%AjMMMQMMMjMMMQUU?338q8MMM%%'',1C%%((-AC2338qJ%% 455:Kn$o#%!"""j0""""###{2###nsZ!7+!EElOOOquu%677<1<OOOO
 
"/"5"5"7"7
 
 
 	//>>>r   rj   c                     |rt          d |D                       nd}g }|D ]9}|r|d         |z  dz  nd}|                    |d         |d         |d           :|S )z<Process tool usage data into a ranked list with percentages.c              3   &   K   | ]}|d          V  dS )rx   Nr5   )r6   ts     r   r   z9InsightsEngine._compute_tool_breakdown.<locals>.<genexpr>+  s&      99!G*999999r   r   rx   d   rw   )r   rx   
percentage)r   r   )rD   rj   total_callsr*   r  pcts         r   rd   z&InsightsEngine._compute_tool_breakdown)  s    =GNc99j999999Q 	 	A6AH1W:+c11qCMM+7!     
 r   rk   c                    |rt          d |D                       nd}|rt          d |D                       nd}||z   }g }|D ]`}|d         |d         z   }|r||z  dz  nd}|                    |d         |d         |d         |||                    d          d	           a|                    d
 d           |||t	          |          d|dS )z3Process per-skill usage into summary + ranked list.c              3   &   K   | ]}|d          V  dS )r   Nr5   r   s     r   r   z:InsightsEngine._compute_skill_breakdown.<locals>.<genexpr>8  s&      EEA,EEEEEEr   r   c              3   &   K   | ]}|d          V  dS )r   Nr5   r   s     r   r   z:InsightsEngine._compute_skill_breakdown.<locals>.<genexpr>9  s'      GGa. 1GGGGGGr   r   r   r  r   r   )r   r   r   total_countr  r   c                 P    | d         | d         | d         | d         pd| d         fS )Nr	  r   r   r   r   r   r5   r   s    r   r   z9InsightsEngine._compute_skill_breakdown.<locals>.<lambda>J  s4    - ,.!.!&Q'
 r   Tr   rJ   rO   )r   r   r$   r   r   )	rD   rk   rK   rL   rM   rQ   r   r	  r  s	            r   re   z'InsightsEngine._compute_skill_breakdown6  sT   IT[CEEEEEEEEZ[KV]CGG;GGGGGG\]/2CC
  
	 
	E-n0EEKFY`+(;;cAA_`Jw#L1 %n 5*( %		. 9 9      	   	 		
 		
 		
 &7%6':(+K(8(8	  %
 
 	
r   c                    t                      t                      t                      }|D ]}|                    d          }|st          j        |          }|                                xx         dz  cc<   |j        xx         dz  cc<   ||                    d          xx         dz  cc<   g dfdt          d          D             }fdt          d          D             }|rt          |d	 
          nd}|rt          |d 
          nd}	t          |          }
|rt          |                                          }d}d}t          dt          |                    D ]a}t          j        ||dz
           d          }t          j        ||         d          }||z
  j        dk    r|dz  }t          ||          }_d}bnd}||||	|
|dS )z2Analyze activity patterns by day of week and hour.r   r3   z%Y-%m-%d)MonTueWedThuFriSatSunc                 N    g | ]!}|                              |d           d"S )r   )dayrx   r   )r6   i
day_counts	day_namess     r   r8   z=InsightsEngine._compute_activity_patterns.<locals>.<listcomp>n  sC     
 
 
 aL:>>!Q+?+?@@
 
 
r      c                 B    g | ]}|                     |d           dS )r   )hourrx   r   )r6   r  hour_countss     r   r8   z=InsightsEngine._compute_activity_patterns.<locals>.<listcomp>s  s?     
 
 
 A!6!677
 
 
r      c                     | d         S Nrx   r5   r   s    r   r   z;InsightsEngine._compute_activity_patterns.<locals>.<lambda>y  s
    qz r   r   Nc                     | d         S r  r5   r   s    r   r   z;InsightsEngine._compute_activity_patterns.<locals>.<lambda>z  s
    7 r   r   )by_dayby_hourbusiest_daybusiest_houractive_days
max_streak)r   r$   r   fromtimestampweekdayr  strftimeranger:   r   r   keysstrptimerG   )rD   ri   daily_countsr   tsdtday_breakdownhour_breakdownr$  r%  r&  	all_datescurrent_streakr'  r  d1d2r  r  r  s                    @@@r   rf   z)InsightsEngine._compute_activity_patterns^  sh   YY
iiyy 	7 	7A|$$B '++Brzz||$$$)$$$   A%   Z00111Q61111EEE	
 
 
 
 
1XX
 
 


 
 
 
2YY
 
 
 GT]c--A-ABBBBY]HV`s>/C/CDDDD\` ,''  	|002233INJ1c)nn-- ' '&yQ'7DD&y|Z@@G>Q&&"a'N!$Z!@!@JJ%&NN' J $%&(&$
 
 	
r   c           	         g }d |D             }|rt          |d           }|d         |d         z
  }|                    d|d         dd	         t          |          t          j        |d                                       d
          d           t          |d           }|                    d          pddk    rs|                    d|d         dd	         |d          d|                    d          r-t          j        |d                                       d
          ndd           t          |d           }|                    d          pd|                    d          pdz   }|dk    rn|                    d|d         dd	         |dd|                    d          r-t          j        |d                                       d
          ndd           t          |d           }	|	                    d          pddk    rs|                    d|	d         dd	         |	d          d|	                    d          r-t          j        |	d                                       d
          ndd           |S )z<Find notable sessions (longest, most messages, most tokens).c                 f    g | ].}|                     d           |                     d          ,|/S )r   r   r   r   s     r   r8   z8InsightsEngine._compute_top_sessions.<locals>.<listcomp>  sN     "
 "
 "
uu\"""
'(uuZ'8'8"
"
 "
 "
r   c                 $    | d         | d         z
  S )Nr   r   r5   r  s    r   r   z6InsightsEngine._compute_top_sessions.<locals>.<lambda>  s    q}q> r   r   r   r   zLongest sessionidN   %b %d)label
session_idvaluedatec                 0    |                      d          pdS )Nr   r   r   r  s    r   r   z6InsightsEngine._compute_top_sessions.<locals>.<lambda>  s    o0F0F0K! r   r   r   zMost messages msgs?c                 `    |                      d          pd|                      d          pdz   S )Nr   r   r   r   r  s    r   r   z6InsightsEngine._compute_top_sessions.<locals>.<lambda>  s.    155005A!%%:P:P:UTUV r   r   r   zMost tokens, tokensc                 0    |                      d          pdS )Nr   r   r   r  s    r   r   z6InsightsEngine._compute_top_sessions.<locals>.<lambda>  s    7H1I1I1NQ r   r   zMost tool callsz calls)r:   r   r.   r   r(  r*  r$   )
rD   ri   topsessions_with_durationlongestdur	most_msgsmost_tokenstoken_total
most_toolss
             r   rg   z$InsightsEngine._compute_top_sessions  s    "
 "
"
 "
 "
 " 	&??  G *%(==CJJ*%dmCRC0)#.. .w|/DEENNwWW	     &K&KLLL	MM/**/a144JJ('ocrc2%o6===]f]j]jkw]x]x  B.y/FGGPPQXYYY  B	     VV
 
 
 #~66;!P_@`@`@edef??JJ&)$/4'2222_j_n_no{_|_|  F.{</HIIRRSZ[[[  CF	     'N'NOOO
NN,--2a77JJ*(.ss3&'89AAA^h^l^lmy^z^z  D.z,/GHHQQRYZZZ  AD	     
r   reportc                    |                     d          rB|                     dd          }|                     d          rd|d          dnd}d| d	| d
S g }|d         }|d         }|                     d          }|                    d           |                    d           |                    d           d| d	}|r	|d| dz  }dt          |          z
  dz
  }|dz  }	||	z
  }
|                    dd|	z   d| dd|
z   d           |                    d           |                    d           |                     d          r|                     d          rt          j        |d                                       d          }t          j        |d                                       d          }|                    d| d|            |                    d           |                    d           |                    d           |                    d|d         dd |d!         d"           |                    d#|d$         d%d&|d'         d"           |                    d(|d)         d%d*|d+         d"           |                    d,|d-         d"           |d.         d/k    rE|                    d0t          |d.         d1z            d2d3t          |d4                               |                    d5|d6         d7           |                    d           |d8         r|                    d9           |                    d           |                    d:d;d<dd=d>dd?d@           |d8         D ]?}|dA         dBdC         }|                    d:|d<d|dD         d>d|d-         dE           @|                    d           t          |dF                   dGk    s |dF         r|dF         d/         dH         dIk    r|                    dJ           |                    d           |                    d:dKdLdd=d>ddMdNdd?dO           |dF         D ]?}|                    d:|dH         dLd|dD         d>d|dP         dQd|d-         dR           @|                    d           |dS         r|                    dT           |                    d           |                    d:dUdVddWd>ddXd>           |dS         dBdY         D ]6}|                    d:|dZ         dVd|d[         d\d|d]         d^dX           7t          |dS                   dYk    r/|                    d_t          |dS                   dYz
   d`           |                    d           |                     dai           }|                     dbg           }|rf|                    dc           |                    d           |                    d:dddVddedfddgdfddhdi           |dBdj         D ]}dk}|                     dl          r-t          j        |dl                                       dm          }|                    d:|dn         dBdC         dVd|do         dpd|dq         dpd|di           |                     dri           }|                    ds|                     dtd/           du|                     dvd/          d"dw|                     dxd/          d"           |                    d           |                     dyi           }|                     dz          r|                    d{           |                    d           d| |dz         D             }t          |dY}          }t          |dz                   D ]8\  }}||         }|                    d:|d~          d:|dd|d[                     9|                    d           t          |d         d d          }d |D             dBd         }|rng }|D ]>}|d         }|dk     rdnd} |dz  pd}!|                    |! |  d|d[          d           ?|                    dd
                    |                      |                     d          r|                    d|d                     |                     d          r+|d         dGk    r|                    d|d          d           |                    d           |                     d          r|                    d           |                    d           |d         D ]>}"|                    d:|"d         dd|"d         dd|"d          d|"d          d	           ?|                    d           d
                    |          S )z6Format the insights report for terminal display (CLI).rS   rG   rF   rR   z
 (source: )r   z   No sessions found in the last z days.rT   u     ╔══════════════════════════════════════════════════════════╗uD     ║                    📊 Hermes Insights                    ║zLast  (:      u     ║ u   ║u     ╚══════════════════════════════════════════════════════════╝r   r   z	%b %d, %Yz
  Period:     — u     📋 Overviewu     ────────────────────────────────────────────────────────z  Sessions:          r   z<12z  Messages:        r   rE  z  Tool calls:        r   z<12,z  User messages:   r   z  Input tokens:      r   z  Output tokens:   r   z  Total tokens:      r   r   r   z  Active time:       ~r   z<11z  Avg session:     ~r   z  Avg msgs/session:  r   .1frU   u     🤖 Models Used  Modelz<30Sessionsz>8Tokensz>12r   N   ri   z>12,rV   r3   r   cliu     📱 PlatformsPlatformz<14Messagesz>10z>14r   z>10,z>14,rW   u     🔧 Top ToolsToolz<28Calls%   r   rx   z>8,r  z>7.1fz
  ... and z more toolsrX   rQ   u     🧠 Top SkillsSkillLoadsz>7Editsz	Last usedz>11
   u   —r   r<  r   r   z>7,r   rP   z  Distinct skills: rN   z	  Loads: rK   z	  Edits: rL   rY   r"  u     📅 Activity Patternsc                     g | ]
}|d          S )rx   r5   )r6   r   s     r   r8   z2InsightsEngine.format_terminal.<locals>.<listcomp>>  s    <<<!G*<<<r   )r1   r  z<15r#  c                     | d         S r  r5   r   s    r   r   z0InsightsEngine.format_terminal.<locals>.<lambda>G  s
    aj r   Tr   c                 *    g | ]}|d          dk    |S )rx   r   r5   )r6   hs     r   r8   z2InsightsEngine.format_terminal.<locals>.<listcomp>H  s!    BBB1W:>>!>>>r      r     AMPMz  Peak hours: z, r&  z  Active days: r'  z  Best streak:  consecutive daysrZ   u     🏆 Notable Sessionsr=  z<20r?  z<18r@  r>  
)r$   r   r   r   r(  r*  r.   r>   	enumerater   join)#rD   rP  rG   srclineso
src_filterperiod_labelpaddingleft_pad	right_pad	start_strend_strmr   pr  rX   rQ   r   	last_usedrP   act
day_valuesbarsr  r   bar
busy_hours	hour_strsrm  hrampm
display_hrr/  s#                                      r   format_terminalzInsightsEngine.format_terminal  s.   ::g 	H::fb))D=CZZ=X=X`9vo69999^`CGdGGGGGG:f~ZZ00
 	R  N  	O  	O  	O[\\\*t*** 	/.....Ls<(((1,a<h&	QS8^QQlQQS9_QQQRRR  N  	O  	O  	OR 55#$$ 	/?)@)@ 	 .q1C/DEENN{[[I,Q/?-@AAJJ;WWGLL?i??g??@@@LL 	&'''&'''pQ/?-@pppYZ[kYlpppqqqrQ/A-Brrr\]^m\nrrrssszQ/C-Dzzz^_`u^vzzz{{{BQ~->BBBCCC]aLL  c2B1]CSVZCZ2[2[  c  c  c  vF  GH  I_  G`  va  va  c  c  d  d  dPQ/I-JPPPQQQR ( 	LL-...LL*+++LLJgJJJJJJJHJJJKKKH% ` `wZ_
^*^^^1Z=^^^aFW^^^____LL vk"##a''F;,?'F;DWXYDZ[eDfjoDoDoLL+,,,LL*+++LL^j^^^z^^^z^^^PX^^^___K( x xv!J-vvva
mvvv:vvv^_`n^ovvvwwwwLL '? 	LL+,,,LL*+++LL@f@@@7@@@@@@AAAG_SbS) ] ][!F)[[[!G*[[[1\?[[[[\\\\6'?##b((P#fWo*>*>*CPPPQQQLL Hb))ZZb11
 	LL,---LL*+++LLWgWWWGWWWWWWkWWWXXX#CRC  !	99^,, ` ( 6u^7L M M V VW^ _ _Ixw,xxx53FxxxUSaMbxxxirxxx    jjB//GLLBgkk2H!&L&L B B!++&91==CB B!++&91==AB B  
 LL jjR((778 	LL3444LL*+++ =<c(m<<<JjB777D!#h-00 F F11gD!E(DDcDDD'
DDEEEELL  I4H4HRVWWWJBBZBBB2A2FJ F	# K KA6B#%7744D!#bBJ$$
%ID%I%IAgJ%I%I%IJJJJDdii	.B.BDDEEEww}%% ECs=/ACCDDDww|$$ U\):Q)>)>Ss</@SSSTTTLL ::n%% 	LL2333LL*+++^, j jh"W+hhhBwKhhhr&zhhUWXdUehhhiiiiLLyyr   c                 V	   |                     d          r|                     dd          }d| dS g }|d         }|d         }|                    d| d           |                    d	|d
          d|d         dd|d         d           |                    d|d         dd|d         dd|d         dd           |d         dk    rD|                    dt          |d         dz             dt          |d                               |                    d           |d         rw|                    d           |d         d d!         D ]<}|                    d"|d#         d d$          d%|d&          d'|d         dd(           =|                    d           t          |d)                   d*k    rg|                    d+           |d)         D ]4}|                    d"|d,          d%|d&          d'|d-         dd.           5|                    d           |d/         rp|                    d0           |d/         d d1         D ]5}|                    d"|d2          d%|d3         dd4|d5         d6d7           6|                    d           |                     d8i           }|                     d9          r|                    d:           |d9         d d!         D ]~}	d}
|	                     d;          r0d<t	          j        |	d;                                       d=           }
|                    d"|	d>          d%|	d?         dd@|	dA         ddB|
            |                    d           |                     dCi           }|                     dD          r|                     dE          r|dE         dF         }|dGk     rdHndI}|dGz  pdG}|                    dJ|dD         dK          dL|dD         d3          dM| | dN|dE         d3          dO
           |                     dP          r|                    dQ|dP                     |                     dRd          d*k    r|                    dS|dR          dT           dU                    |          S )Vz;Format the insights report for gateway/messaging (shorter).rS   rG   rF   zNo sessions found in the last z days.rT   u"   📊 **Hermes Insights** — Last z days
z**Sessions:** r   z | **Messages:** r   rE  z | **Tool calls:** r   z**Tokens:** r   z (in: r   z / out: r   rR  r   r   z**Active time:** ~r   z | **Avg session:** ~r   r   rU   u   **🤖 Models:**Nrn  rZ  r      rX  ri   z sessions, rF  rV   r3   u   **📱 Platforms:**r   r   rB  rW   u   **🔧 Top Tools:**   r   rx   z calls (r  rY  z%)rX   rQ   u   **🧠 Top Skills:**r   z, last used r<  r   r   z loads, r   z editsrY   r$  r%  r  ro  rp  rq  u   **📅 Busiest:** r  zs (z sessions), rT  z
 sessions)r&  z**Active days:** r'  z**Best streak:** rr  rs  )r$   r   r.   r   r   r(  r*  ru  )rD   rP  rG   rw  rx  r  r  r  rX   r   suffixr  r  r  r  s                  r   format_gatewayzInsightsEngine.format_gatewayb  s)   ::g 	A::fb))D@D@@@@:f~G$GGGHHH 	  Pa(8&9  P  PAN^L_  P  P  Pvw  yK  wL  P  P  P  	Q  	Q  	QAn$5qAU?Vbcdybz  	A  	A  	A]aLL  \.>q?ORV?V.W.W  \  \n~  @A  BX  @Y  oZ  oZ  \  \  ]  ]  ]R ( 	LL+,,,H%bqb) p pn!G*SbS/nn*nnRSTbRcnnnnooooLL vk"##a''LL.///K( h hf!J-ffa
mffPQR\P]ffffggggLL '? 	LL.///G_RaR( a a_!F)__!G*___,____````LLHb))::l## 		LL/000-bqb1  99^,, nmH,B5CX,Y,Y,b,bcj,k,kmmFtwtteL.AtttUSaMbtttlrtt    LL jjR((77=!! 	Wcggn&=&= 	W^$V,B7744DbBJLL  rc-.@.G  r  rCP]L^_fLg  r  ru  r  BF  r  r  JM  N\  J]  ^e  Jf  r  r  r  s  s  sww}%% IE]1CEEHHHww|Q''!++U\1BUUUVVVyyr   )rF   N)N)__name__
__module____qualname____doc__rE   r;   r}   r   r   rm   _SESSION_COLSrr   rs   r%   r   r]   r^   r_   r`   ra   rb   rc   rd   re   rf   rg   r  r  r5   r   r   r@   r@   ]   s          >
 >
S >
s >
d38n >
 >
 >
 >
JAM	$- 	$ 	$ 	$ 	$- 	$ 	$ 	$ 8 8E 83 8$t* 8 8 8 8Z
 Z
e Z
S Z
DJ Z
 Z
 Z
 Z
xJ+ J+u J+c J+T$Z J+ J+ J+ J+X
 
 
 
t 
 
 
 
HH
$t* H
T H
d H
 H
 H
 H
T#d #T
 # # # #JDJ 4:    >$t* d    &
DJ &
4S> &
 &
 &
 &
P8
4: 8
$ 8
 8
 8
 8
t8d4j 8T$Z 8 8 8 8|J d J s J  J  J  J X@ T @ c @  @  @  @  @  @ r   r@   )NN)r   r   )r/   )r  r~   r\   collectionsr   r   r   typingr   r   r   agent.usage_pricingr	   r
   r   r   r   _DEFAULT_PRICINGr}   boolr   r;   tupler%   r+   r.   r>   r@   r5   r   r   <module>r     s0   $   , , , , , , , ,       " " " " " " " " " "              # O O3 O# O OW[ O O O O $:
 $: $: $:38ns*$:$: $:
 $: $: $: $: 5#:$: $: $: $:N,e , , , , ,
X XtCy XS X$s) X X X XE  E  E  E  E  E  E  E  E  E r   