
    ՞i#                        U d Z ddlmZ ddlZddlZddlmZmZ  ej                  e	      Z
 G d d      Z G d d      Zdad	ed
<   ddZy)u4  
core/observability/langfuse_client.py

Langfuse client wrapper for Genesis LLM observability.

Provides trace, span, and generation tracking for all agent operations.
Falls back to a no-op stub when the Langfuse SDK is unavailable or keys
are absent — zero production breakage on import failure.

Usage:
    from core.observability.langfuse_client import get_tracer

    tracer = get_tracer()
    trace = tracer.trace("agent_run", metadata={"agent": "scout"})
    tracer.generation(
        trace_id=trace.id,
        name="gemini_call",
        model="gemini-flash",
        prompt="Summarise X",
        completion="Summary...",
        usage={"input": 120, "output": 40},
    )
    tracer.flush()

VERIFICATION_STAMP
Story: OBS-002
Verified By: parallel-builder
Verified At: 2026-02-25
Tests: 21/21
Coverage: 100%
    )annotationsN)AnyOptionalc                  8    e Zd ZdZddZd	dZd	dZd	dZd
dZy)
_NoOpTracezStub trace returned when Langfuse is unavailable.

    Exposes the same surface as a real Langfuse Trace so callers never need
    conditional branches.
    c                &    || _         d| | _        y )Nznoop-)nameid)selfr	   s     ;/mnt/e/genesis-system/core/observability/langfuse_client.py__init__z_NoOpTrace.__init__6   s    	$.    c                    | S N r   kwargss     r   spanz_NoOpTrace.span;       r   c                    | S r   r   r   s     r   
generationz_NoOpTrace.generation>   r   r   c                    | S r   r   r   s     r   updatez_NoOpTrace.updateA   r   r   c                     y r   r   r   s    r   endz_NoOpTrace.endD   s    r   N)r	   strreturnNone)r   r   r   z'_NoOpTrace'r   r   )	__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   r   r   /   s     !
r   r   c                      e Zd ZdZ	 	 	 	 d	 	 	 	 	 	 	 	 	 d	dZ	 	 	 d
	 	 	 	 	 	 	 	 	 ddZ	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 d
	 	 	 	 	 	 	 	 	 	 	 ddZddZy)GenesisTracerax  
    Wraps the Langfuse SDK for LLM trace management across Genesis agents.

    Parameters
    ----------
    public_key : str, optional
        Langfuse public key. Falls back to ``LANGFUSE_PUBLIC_KEY`` env var.
    secret_key : str, optional
        Langfuse secret key. Falls back to ``LANGFUSE_SECRET_KEY`` env var.
    host : str, optional
        Langfuse host URL. Falls back to ``LANGFUSE_HOST`` env var, then
        ``"http://localhost:3000"`` (self-hosted default).
    enabled : bool
        Set to ``False`` to disable all tracing entirely (useful in tests
        that want pure no-op behaviour without mocking).
    Nc                <   || _         d | _        |st        j                  d       y |xs t        j
                  j                  d      }|xs t        j
                  j                  d      }|xs  t        j
                  j                  dd      }|r|st        j                  d       y 	 ddlm}  ||||	      | _        t        j                  d
|       y # t        $ r t        j                  d       Y y t        $ r t        j                  dd       Y y w xY w)Nz)GenesisTracer: tracing disabled by callerLANGFUSE_PUBLIC_KEYLANGFUSE_SECRET_KEYLANGFUSE_HOSTzhttp://localhost:3000uK   GenesisTracer: LANGFUSE_PUBLIC_KEY / SECRET_KEY absent — tracing disabledr   )Langfuse)
public_key
secret_keyhostz0GenesisTracer: Langfuse client initialised at %sui   GenesisTracer: 'langfuse' package not installed — install with `pip install langfuse` to enable tracingu8   GenesisTracer: Langfuse init failed — tracing disabledT)exc_info)enabled_clientloggerdebugosenvirongetlangfuser+   infoImportErrorwarning	Exception)	r   r,   r-   r.   r0   pkskhr+   s	            r   r   zGenesisTracer.__init___   s      LLDE@2::>>*?@@2::>>*?@LBJJNN?4KLrLLfg	)#rbqIDLKKJAN 	NNH  	NNJ  	s   ,,C D9DDc                    | j                   t        |      S 	 | j                   j                  ||xs i ||      S # t        $ r$ t        j                  d|       t        |      cY S w xY w)u  
        Start a new top-level trace.

        Parameters
        ----------
        name : str
            Human-readable trace name (e.g. ``"agent_spawn"``).
        metadata : dict, optional
            Arbitrary key-value pairs attached to the trace.
        user_id : str, optional
            End-user or customer identifier for attribution.
        session_id : str, optional
            Session identifier (maps to a Langfuse session).

        Returns
        -------
        Langfuse Trace or ``_NoOpTrace``
            Always returns an object with a ``.id`` attribute — callers
            never need to guard against ``None``.
        )r	   metadatauser_id
session_idz*GenesisTracer: failed to create trace '%s')r1   r   tracer;   r2   	exception)r   r	   r@   rA   rB   s        r   rC   zGenesisTracer.trace   sw    6 <<d##		$<<%%!R%	 &    	$I4Pd##	$s   "< *A)(A)c           
         | j                   t        j                  d||       y	 | j                   j                  ||||||xs i |xs i        y# t        $ r t        j                  d|       Y yw xY w)u  
        Record an LLM generation (prompt → completion with token usage).

        Parameters
        ----------
        trace_id : str
            Parent trace id (from ``trace().id``).
        name : str
            Generation name (e.g. ``"gemini_summarise"``).
        model : str
            Model identifier (e.g. ``"gemini-flash"``).
        prompt : Any
            The input sent to the model (str, list, dict).
        completion : Any
            The model's response.
        usage : dict, optional
            Token counts: ``{"input": N, "output": N}`` or Langfuse-native
            ``UsageInput`` dict.
        metadata : dict, optional
            Additional key-value context.
        Nz6GenesisTracer: generation '%s' on trace %s (no client))trace_idr	   modelinputoutputusager@   z/GenesisTracer: failed to record generation '%s')r1   r2   r3   r   r;   rD   )r   rF   r	   rG   prompt
completionrJ   r@   s           r   r   zGenesisTracer.generation   s    > <<LLH$PX 	VLL##!!kr!R $   	VNPTU	Vs   *A A32A3c                    | j                   y	 | j                   j                  |||||xs i        y# t        $ r t        j	                  d|       Y yw xY w)z
        Record a span (non-LLM sub-operation within a trace).

        Typical use: tool calls, database queries, HTTP requests.
        N)rF   r	   rH   rI   r@   z)GenesisTracer: failed to record span '%s')r1   r   r;   r2   rD   )r   rF   r	   rH   rI   r@   s         r   r   zGenesisTracer.span   se     <<		PLL!!R    	PH$O	Ps   $4 AAc                    | j                   	 | j                   j                          yy# t        $ r t        j	                  d       Y yw xY w)z
        Flush all pending events to the Langfuse backend.

        Call before process exit or after a batch of generations to ensure
        no events are silently dropped.
        NzGenesisTracer: flush failed)r1   flushr;   r2   rD   r   s    r   rO   zGenesisTracer.flush   sK     <<#@""$ $  @  !>?@s   * A
A)NNNT)
r,   Optional[str]r-   rP   r.   rP   r0   boolr   r   )NNN)
r	   r   r@   Optional[dict]rA   rP   rB   rP   r   r   )NN)rF   r   r	   r   rG   r   rK   r   rL   r   rJ   rR   r@   rR   r   r   )rF   r   r	   r   rH   r   rI   r   r@   rR   r   r   r    )	r!   r"   r#   r$   r   rC   r   r   rO   r   r   r   r&   r&   M   sH   & %)$("$!$ "$ 	$
 $ 
$Z $(!%$('$'$ !'$ 	'$
 "'$ 
'$` !%#'0V0V 0V 	0V
 0V 0V 0V !0V 
0Vl #'PP P 	P
 P !P 
P6@r   r&   zOptional[GenesisTracer]_tracerc                 .    t         
t               a t         S )u  
    Return the module-level ``GenesisTracer`` singleton.

    The instance is created lazily on first call using environment variables
    for credentials.  Subsequent calls return the same object — safe to call
    from any module without importing a shared reference.
    )rS   r&   r   r   r   
get_tracerrU     s     /Nr   )r   r&   )r$   
__future__r   loggingr4   typingr   r   	getLoggerr!   r2   r   r&   rS   __annotations__rU   r   r   r   <module>r[      sV   @ #  	  			8	$ <}@ }@H $(	  'r   