
    "֞iQ$                       U d Z ddlmZ ddlZddlZddlZddlmZ ddlmZm	Z	 ddl
mZ  ej                  e      Zi 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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
d"d#d d
d$d%d d
Zd&ed'<   d(dd
Zd)ed*<   d+Zd2d,Z G d- d.      Zdad/ed0<   d3d1Zy)4aO  
core/observability/cost_tracker.py

LLM cost attribution and tracking for Genesis observability layer.

This module complements ``core/cost_tracker_v2.py`` (which gates execution
against budget limits) by providing Langfuse-aligned session/agent/customer
cost attribution and a JSONL audit trail.

Pricing is per 1M tokens (industry-standard notation).

Usage:
    from core.observability.cost_tracker import CostTracker

    tracker = CostTracker()
    cost = tracker.record(
        model="gemini-flash",
        input_tokens=1200,
        output_tokens=400,
        session_id="sess-abc",
        agent_id="scout-01",
        customer_id="cust-xyz",
    )
    print(f"Cost: ${cost:.6f}")
    print(tracker.get_cost_summary())

VERIFICATION_STAMP
Story: OBS-004
Verified By: parallel-builder
Verified At: 2026-02-25
Tests: 21/21
Coverage: 100%
    )annotationsN)defaultdict)datetimetimezone)Optionalzclaude-opus-4-6g      .@g     R@)inputoutputzclaude-sonnet-4-6g      @zclaude-haiku-4-5g?g      @zclaude-opus-4-5zclaude-sonnet-4zclaude-haikuzgemini-2.5-prog      ?g      $@zgemini-2.5-flashg333333?g333333?zgemini-2.0-flashzgemini-1.5-prog      @zgemini-1.5-flashz
gemini-prozgemini-flashztext-embedding-004        znomic-embed-textztext-embedding-3-smallg{Gz?ztext-embedding-3-largegp=
ף?zdict[str, dict[str, float]]MODEL_PRICINGg      ?dict[str, float]_DEFAULT_PRICINGz7/mnt/e/genesis-system/data/observability/cost_log.jsonlc                H   | j                         j                         }|t        v r	t        |   S t        j                         D cg c]  \  }}||v s||v st	        |      |f }}}|rt        |d       d   S t        j                  d| t               t        S c c}}w )z
    Return the pricing dict for a model name.

    Performs a case-insensitive substring match so that version suffixes and
    provider prefixes (e.g. ``"openrouter/gemini-flash"``) are handled.
    c                    | d   S )Nr    )xs    8/mnt/e/genesis-system/core/observability/cost_tracker.py<lambda>z"_resolve_pricing.<locals>.<lambda>c   s
    QqT     )key   u<   CostTracker: unknown model '%s' — using default pricing %s)	lowerstripr   itemslenmaxloggerwarningr   )modelr   kv
candidatess        r   _resolve_pricingr"   Q   s     ++-


C mS!! !. 3 3 51cSAXQJ  :>2155
NNF
 s   BBc                  v    e Zd ZdZefddZ	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddZddZddZ	ddZ
dd	Zdd
Zy)CostTrackeraU  
    Tracks LLM API costs with per-session, per-agent, and per-customer attribution.

    Instances are lightweight and can be created per-request or shared as a
    singleton via ``get_cost_tracker()``.

    Parameters
    ----------
    log_path : str
        Path to the JSONL audit file.  Parent directory is created on first write.
    c                    || _         t        t              | _        t        t              | _        t        t              | _        y )N)log_pathr   float_session_costs_agent_costs_customer_costs)selfr&   s     r   __init__zCostTracker.__init__z   s0     0;E0B.9%.@1<U1Cr   Nc           	        t        |      }t        |dz  |d   z  |dz  |d   z  z   d      }|r| j                  |xx   |z  cc<   |r| j                  |xx   |z  cc<   |r| j                  |xx   |z  cc<   t        j                  t        j                        j                         |||||||d}	| j                  |	       |S )a  
        Record one generation's cost and append to the JSONL audit log.

        Parameters
        ----------
        model : str
            Model name (e.g. ``"gemini-flash"``).
        input_tokens : int
            Number of prompt/input tokens consumed.
        output_tokens : int
            Number of completion/output tokens produced.
        session_id : str, optional
            Session identifier (maps to Langfuse session).
        agent_id : str, optional
            Genesis agent identifier.
        customer_id : str, optional
            Customer / SubAIVA identifier for billing attribution.

        Returns
        -------
        float
            Computed cost in USD (rounded to 6 decimal places).
        i@B r   r	      )	timestampr   input_tokensoutput_tokenscost_usd
session_idagent_idcustomer_id)r"   roundr(   r)   r*   r   nowr   utc	isoformat_append_log)
r+   r   r0   r1   r3   r4   r5   pricingcostentrys
             r   recordzCostTracker.record   s    @ #5)I%)99y(GH,==>
 
+t3+h'4/'  -5- "hll3==?(*$ &	
 	r   c                :    | j                   j                  |d      S )z/Return total cost accumulated for *session_id*.r
   )r(   get)r+   r3   s     r   get_session_costzCostTracker.get_session_cost   s    ""&&z377r   c                :    | j                   j                  |d      S )z-Return total cost accumulated for *agent_id*.r
   )r)   r@   )r+   r4   s     r   get_agent_costzCostTracker.get_agent_cost   s      $$Xs33r   c                :    | j                   j                  |d      S )z0Return total cost accumulated for *customer_id*.r
   )r*   r@   )r+   r5   s     r   get_customer_costzCostTracker.get_customer_cost   s    ##''S99r   c                \    t        t        | j                  j                               d      S )z
        Return total cost across all tracked sessions in this instance.

        Note: this reflects in-memory state only; it does not read from the
        JSONL file.  For persistent totals, read ``cost_log.jsonl`` directly.
        r.   )r6   sumr(   valuesr+   s    r   get_daily_totalzCostTracker.get_daily_total   s%     S,,3356::r   c                    t        | j                         d      t        | j                        t        | j                        t        | j
                        dS )z
        Return a summary dict with all attribution breakdowns.

        Returns
        -------
        dict
            Keys: ``daily_total_usd``, ``sessions``, ``agents``, ``customers``.
           )daily_total_usdsessionsagents	customers)r6   rJ   dictr(   r)   r*   rI   s    r   get_cost_summaryzCostTracker.get_cost_summary   sK      %T%9%9%;Q?T0014,,-d223	
 	
r   c                   	 t        j                  t         j                  j                  | j                        d       t        | j                  dd      5 }|j                  t        j                  |      dz          ddd       y# 1 sw Y   yxY w# t        $ r# t        j                  d| j                         Y yw xY w)	zAAppend a JSONL record to the audit file, creating dirs as needed.T)exist_okazutf-8)encoding
Nz+CostTracker: failed to write cost log at %s)osmakedirspathdirnamer&   openwritejsondumpsOSErrorr   	exception)r+   r=   fhs      r   r:   zCostTracker._append_log   s    	[KK6FdmmS7; 3rE*T123 3 3 	[JDMMZ	[s0   AB (B	 B 	BB B )C C)r&   strreturnNone)NNN)r   rc   r0   intr1   rf   r3   Optional[str]r4   rg   r5   rg   rd   r'   )r3   rc   rd   r'   )r4   rc   rd   r'   )r5   rc   rd   r'   )rd   r'   )rd   rQ   )r=   rQ   rd   re   )__name__
__module____qualname____doc__COST_LOG_PATHr,   r>   rA   rC   rE   rJ   rR   r:   r   r   r   r$   r$   m   s    
 (5 D  %)"&%)<< < 	<
 "<  < #< 
<D84:;
([r   r$   zOptional[CostTracker]_cost_trackerc                 .    t         
t               a t         S )z2Return the module-level ``CostTracker`` singleton.)rm   r$   r   r   r   get_cost_trackerro     s     #r   )r   rc   rd   r   )rd   r$   )rk   
__future__r   r^   loggingrX   collectionsr   r   r   typingr   	getLoggerrh   r   r   __annotations__r   rl   r"   r$   rm   ro   r   r   r   <module>rv      s   D #   	 # ' 			8	$.DT:. CT:. DS9	.
 DT:. CT:. DS9. DT:. ET:. ET:. DS9. ET:. DS9. ET:." CC"@#.$ CC"@%.& DC"@'.( DC"@).* 0 03c%B " B J8J[ J[b (,$ +r   