
    $jh                         d Z ddlZddlZddlZddlZddlZddlZddlZddlm	Z	 ddl
mZ ddlZddlmZmZmZmZ 	 ddlZddlmZ dZn# e$ r dZY nw xY wd	d
lmZmZmZmZmZ d	dlmZ ddl m!Z! dZ" ej#        e$          Z% ej#        d          &                    ej'                    e( ej)        e e*e                              Z+ ej,        e+          Z-de*dz  de*dz  fdZ. G d de/          Z0de*defdZ1 e2h d          Z3de*de4fdZ5	 	 	 	 	 	 	 	 	 d,de*de*de*de*de*de*dz  de*dz  d e6e*ef         dz  d!e6e*e*f         dz  d"e*dz  d#e*dz  d$ed%e7dz  d&e6e*ef         dz  defd'Z8 G d( d)          Z9 G d* d+          Z:e9Z;dS )-z9
LLM wrapper for unified configuration across providers.
    N)Path)Any)APIConnectionErrorAPIStatusErrorAsyncOpenAILengthFinishReasonError)service_accountTF   )DEFAULT_LLM_MAX_CONCURRENTDEFAULT_LLM_TIMEOUTENV_LLM_GROQ_SERVICE_TIERENV_LLM_MAX_CONCURRENTENV_LLM_TIMEOUT)get_metrics_collector   )
TokenUsagei  httpxtextreturnc                 >    | dS | s| S t          j        dd|           S )a  
    Sanitize text by removing characters that break downstream systems.

    Removes:
    - ASCII control characters (0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F): break
      json.loads and PostgreSQL UTF-8 encoding; tab (0x09), newline (0x0A), and
      carriage return (0x0D) are preserved as they are valid in text and JSON.
    - Unicode surrogates (U+D800-U+DFFF): Invalid in UTF-8, break LLM APIs

    Surrogate characters are used in UTF-16 encoding but cannot be encoded
    in UTF-8. They can appear in Python strings from improperly decoded data
    (e.g., from JavaScript or broken files). Control characters commonly appear
    in LLM output embedded inside JSON string values.
    Nz-[\x00-\x08\x0b\x0c\x0e-\x1f\x7f\ud800-\udfff] )resub)r   s    h/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/hindsight_api/engine/llm_wrapper.pysanitize_llm_outputr   3   s0     |t 6BBMMM    c                       e Zd ZdZdS )OutputTooLongErrora	  
    Bridge exception raised when LLM output exceeds token limits.

    This wraps provider-specific errors (e.g., OpenAI's LengthFinishReasonError)
    to allow callers to handle output length issues without depending on
    provider-specific implementations.
    N)__name__
__module____qualname____doc__ r   r   r   r   I   s          	Dr   r   rawc                    |                                  }|                    d          r]d|v r|                    dd          d         n	|dd         }|                    d          r
|dd         }|                                 }	 t	          j        |          S # t          j        $ r- t          j        dd|          }t	          j        |          cY S w xY w)	u  
    Robustly parse JSON returned by an LLM.

    Handles common LLM output quirks:
    1. Markdown code fences (```json ... ```) — strip them before parsing.
    2. Embedded control characters (\x00-\x1f, \x7f) — replace with space
       and retry if the initial parse fails.

    Args:
        raw: Raw text returned by the LLM.

    Returns:
        Parsed Python object (dict, list, etc.).

    Raises:
        json.JSONDecodeError: If the text cannot be parsed even after cleanup.
    z```
r      Nz[\x00-\x1f\x7f] )	strip
startswithsplitendswithjsonloadsJSONDecodeErrorr   r   )r$   r   cleaneds      r   parse_llm_jsonr2   U   s    $ 99;;D u )-tzz$""1%%48== 	9Dzz||#z$ # # # &+S$77z'"""""	#s   B 9CC>   mocknoneollamabedrocklitellmllamacpplmstudiovertexailitellmrouterclaude-codeopenai-codexproviderc                 8    |                                  t          vS )zAReturn True if the given provider requires an API key to operate.)lower_PROVIDERS_WITHOUT_API_KEY)r>   s    r   requires_api_keyrB      s    >>#===r   api_keybase_urlmodelreasoning_effortgroq_service_tieropenai_service_tier
extra_bodydefault_headersvertexai_project_idvertexai_regionvertexai_credentialsgemini_safety_settingslitellmrouter_configc                 :   ddl m} ddlm}m}m}m}m}m}m	}m
}m}m} |                                 }|dk    r || ||||          S |dk    r || ||||          S |dk    r || ||||          S |dk    r || ||||          S |d	v r || |||||	|
||
	  	        S |dk    r || |||||          S |dk    r || ||||          S |dk    r"|st          d           || |||||          S |dk    r,|                    d          r|nd| } || ||||          S |dk    rDddlm}  |            } || |||||j        |j        |j        |j        |j        |j                  S |dv r || |||||||          S t          d|            )a  
    Factory function to create the appropriate LLM provider implementation.

    Args:
        provider: Provider name ("openai", "groq", "ollama", "gemini", "anthropic", etc.).
        api_key: API key (may be None for local providers or OAuth providers).
        base_url: Base URL for the API.
        model: Model name.
        reasoning_effort: Reasoning effort level for supported providers.
        groq_service_tier: Groq service tier (for Groq provider) - "on_demand", "flex", or "auto".
        openai_service_tier: OpenAI service tier (for OpenAI provider) - None (default) or "flex" (50% cheaper).
        extra_body: Extra body params merged into OpenAI-compatible API calls.
        default_headers: Custom headers passed as ``default_headers`` to provider SDK clients
            (used by operators routing through proxies / request-tracing middleware). Currently
            wired into the Anthropic provider; other providers may opt in as needed.
        vertexai_project_id: Vertex AI project ID (for VertexAI provider).
        vertexai_region: Vertex AI region (for VertexAI provider).
        vertexai_credentials: Vertex AI credentials object (for VertexAI provider).

    Returns:
        LLMInterface implementation for the specified provider.
    r   )LLMInterface)
AnthropicLLMClaudeCodeLLMCodexLLM	GeminiLLM
LiteLLMLLMLiteLLMRouterLLMLlamaCppLLMMockLLMNoneLLMOpenAICompatibleLLMr=   )r>   rC   rD   rE   rF   r<   r3   r4   geminir:   )	r>   rC   rD   rE   rF   rK   rL   rM   rN   	anthropic)r>   rC   rD   rE   rF   rJ   r7   r;   zProvider 'litellmrouter' requires a config object. Set HINDSIGHT_API_LLM_LITELLMROUTER_CONFIG (or the per-op variant) to a JSON object accepted by litellm.Router. See https://docs.litellm.ai/docs/routing.)r>   rC   rD   rE   configrF   r6   zbedrock/r8   r
   
get_config)r>   rC   rD   rE   rF   
model_path
gpu_layerscontext_sizechat_format
no_grammar
extra_args)	openaigroqr5   r9   minimaxdeepseekvolcano
openrouterzai)r>   rC   rD   rE   rF   rG   rH   rI   zUnknown provider: )llm_interfacerQ   	providersrR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r@   
ValueErrorr+   r_   ra   llamacpp_model_pathllamacpp_gpu_layersllamacpp_context_sizellamacpp_chat_formatllamacpp_no_grammarllamacpp_extra_args)r>   rC   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   provider_lowerbedrock_modelra   r_   s                                r   create_llm_providerrz      s   L ,+++++                        ^^%%N''x-
 
 
 	
 
=	(	(}-
 
 
 	
 
6	!	!w-
 
 
 	
 
6	!	!w-
 
 
 	
 
1	1	1y- 3+!5#9

 

 

 
	
 
;	&	&|-+
 
 
 	
 
9	$	$z-
 
 
 	
 
?	*	*# 	<    '-
 
 
 	
 
9	$	$!&!1!1*!=!=UCUeCUCUz-
 
 
 	
 
:	%	%''''''{-115311
 
 
 	
 
 
 

 

 #"-/ 3!	
 	
 	
 		
 8h88999r   c                      e Zd ZdZ	 	 	 	 	 	 	 d9dededededed	edz  d
edz  dedz  deeef         dz  deeef         dz  deeef         dz  fdZe	defd            Z
e	defd            Zd:dZ	 	 	 	 	 	 	 	 	 	 d;deeeef                  dedz  dedz  dedz  dededed ed!ed"ed#edefd$Z	 	 	 	 	 	 	 d<deeeef                  d%eeeef                  dedz  dedz  dededed ed)eeeef         z  dd*fd+Zd,eddfd-Zd.eddfd/Zdee         fd0Zd:d1Zdeeef         fd2Zd:d3Zd4edd5fd6Zd:d7Zed=d8            ZdS )>LLMProviderzc
    Unified LLM provider.

    Supports OpenAI, Groq, Ollama (OpenAI-compatible), and Gemini.
    lowNr>   rC   rD   rE   rF   rG   rH   rN   rI   rJ   rO   c                    |                                 | _        || _        || _        || _        || _        || _        || _        || _        || _	        |	| _
        |
| _        | j        ,ddlm} 	  |            j        | _        n# t          $ r Y nw xY wg d}| j        |vr-t!          d| j         dd                    |                     | j        s| j        dk    rd	| _        nq| j        d
k    rd| _        n^| j        dk    rd| _        nK| j        dk    rd| _        n8| j        dk    rd| _        n%| j        dk    rd| _        n| j        dk    rd| _        d}d}d}| j        dk    rddlm}  |            }|j        }|st!          d          |j        pd}|j        }|rUt,          st!          d          t.          j                            |dg          }t4                              d|            | j                            d          r!| j        t;          d          d         | _        t4                              d| d | d!| j         d"|rd#nd$            | j        d%v r5| j	        .ddlm} 	  |            }|j        | _	        n# t          $ r Y nw xY w| j        }| j        d&k    r+|)ddlm} 	  |            j        }n# t          $ r d}Y nw xY wtA          | j        | j        | j        | j        | j        | j        | j        | j
        | j        |||| j	        |'          | _!        g | _"        d| _#        dS )(u  
        Initialize LLM provider.

        Args:
            provider: Provider name ("openai", "groq", "ollama", "gemini", "anthropic", "lmstudio").
            api_key: API key.
            base_url: Base URL for the API.
            model: Model name.
            reasoning_effort: Reasoning effort level for supported providers.
            groq_service_tier: Groq service tier ("on_demand", "flex", "auto") - from config.
            openai_service_tier: OpenAI service tier (None or "flex") - from config.
            gemini_safety_settings: Safety settings for Gemini/VertexAI providers.
            extra_body: Extra body params merged into OpenAI-compatible API calls.
            default_headers: Custom headers passed as ``default_headers`` to provider SDK clients.
                Used by operators routing through proxies / request-tracing middleware. Falls
                back to ``HindsightConfig.llm_default_headers`` (env: ``HINDSIGHT_API_LLM_DEFAULT_HEADERS``)
                when ``None``.
            litellmrouter_config: Provider-specific config for ``provider="litellmrouter"``.
                JSON object passed verbatim to ``litellm.Router(**config)`` — see
                https://docs.litellm.ai/docs/routing. Ignored unless ``provider == "litellmrouter"``.
                When None and the provider is ``litellmrouter``, falls back to
                ``HindsightConfig.llm_litellmrouter_config``.
        Nr
   )_get_raw_config)rh   ri   r5   r]   r^   r9   r8   r:   r=   r<   r3   r4   rj   rk   r7   r;   r6   rl   rm   rn   zInvalid LLM provider: z. Must be one of: z, ri   zhttps://api.groq.com/openai/v1r5   zhttp://localhost:11434/v1r9   zhttp://localhost:1234/v1rj   zhttps://api.minimax.io/v1rk   zhttps://api.deepseek.comrm   zhttps://openrouter.ai/api/v1rn   z#https://api.z.ai/api/coding/paas/v4r:   r`   zhHINDSIGHT_API_LLM_VERTEXAI_PROJECT_ID is required for Vertex AI provider. Set it to your GCP project ID.zus-central1zdVertex AI service account auth requires 'google-auth' package. Install with: pip install google-authz.https://www.googleapis.com/auth/cloud-platform)scopesz&Vertex AI: Using service account key: zgoogle/zVertex AI: project=z	, region=z, model=z, auth=r	   ADCr\   r;   )r>   rC   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   )$r@   r>   rC   rD   rE   rF   rO   rG   rH   rN   rI   rJ   r_   r   llm_default_headers	Exceptionrq   joinra   llm_vertexai_project_idllm_vertexai_region llm_vertexai_service_account_keyVERTEXAI_AVAILABLEr	   Credentialsfrom_service_account_fileloggerinfor+   lenllm_gemini_safety_settingsllm_litellmrouter_configrz   _provider_impl_mock_calls_mock_response)selfr>   rC   rD   rE   rF   rG   rH   rN   rI   rJ   rO   r   valid_providersrK   rL   rM   ra   r_   service_account_key
raw_configrouter_configs                         r   __init__zLLMProvider.__init__X  s   J !(( 
 0$8!!2#6 &<#$  /'000000'6'8'8'L$$   
 
 
, =//sdmssW[W`W`apWqWqssttt } 	F}&& @(** ;*,, :)++ ;*,, :,.. >%'' E ##=J&&++++++Z\\F"("@&  5  
 %8IMO"("I # 
\) $@   (7'B'\'\'LM (] ( ($ ZEXZZ[[[ z$$Y// :!ZI(8(89
KKb&9 b bO b bb bAT,_,=,=Z_b b   =222t7R7Z000000,_..
.8.S++    04/H=O++0E000000% / 1 1 J % % % $% 2]L]*!2"4 $ 8 0 3+!5#'#>!.
 
 
$ (*#'s6   .B 
BB9J 
JJ;K KKr   c                 T    ddl m} t          | j        |          r| j        j        S dS )aX  
        Get the OpenAI client for OpenAI-compatible providers.

        This property provides backward compatibility for code that directly accesses
        the _client attribute (e.g., benchmarks, memory_engine).

        Returns:
            AsyncOpenAI client instance for OpenAI-compatible providers, or None for other providers.
        r   )r[   N)providers.openai_compatible_llmr[   
isinstancer   _client)r   r[   s     r   r   zLLMProvider._client  s>     	IHHHHHd)+>?? 	/&..tr   c                 T    ddl m} t          | j        |          r| j        j        S dS )a3  
        Get the Gemini client for Gemini/VertexAI providers.

        This property provides backward compatibility for code that directly accesses
        the _gemini_client attribute.

        Returns:
            genai.Client instance for Gemini/VertexAI providers, or None for other providers.
        r   )rU   N)providers.gemini_llmrU   r   r   r   )r   rU   s     r   _gemini_clientzLLMProvider._gemini_client+  s<     	433333d)955 	/&..tr   c                 H   K   | j                                          d{V  dS )z
        Verify that the LLM provider is configured correctly by making a simple test call.

        Raises:
            RuntimeError: If the connection test fails.
        N)r   verify_connectionr   s    r   r   zLLMProvider.verify_connection<  s5       !3355555555555r   memory
         ?      N@Fmessagesresponse_formatmax_completion_tokenstemperaturescopemax_retriesinitial_backoffmax_backoffskip_validationstrict_schemareturn_usagec                   K   ddl m} |dnd} |d| j         d| |            t          4 d{V  | j                            |||||||||	|
|           d{V }| j        d	k    r9d
dlm} t          | j        |          r| j        	                                | _
        |cddd          d{V  S # 1 d{V swxY w Y   dS )a  
        Make an LLM API call with retry logic.

        Args:
            messages: List of message dicts with 'role' and 'content'.
            response_format: Optional Pydantic model for structured output.
            max_completion_tokens: Maximum tokens in response.
            temperature: Sampling temperature (0.0-2.0).
            scope: Scope identifier for tracking.
            max_retries: Maximum retry attempts.
            initial_backoff: Initial backoff time in seconds.
            max_backoff: Maximum backoff time in seconds.
            skip_validation: Return raw JSON without Pydantic validation.
            strict_schema: Use strict JSON schema enforcement (OpenAI only). Guarantees all required fields.
            return_usage: If True, return tuple (result, TokenUsage) instead of just result.

        Returns:
            If return_usage=False: Parsed response if response_format is provided, otherwise text content.
            If return_usage=True: Tuple of (result, TokenUsage) with token counts from the LLM call.

        Raises:
            OutputTooLongError: If output exceeds token limits.
            Exception: Re-raises API errors after retries exhausted.
        r
   	set_stageNz+structuredr   llm..)r   r   r   r   r   r   r   r   r   r   r   r3   r   rY   )worker.stager   r>   _global_llm_semaphorer   callproviders.mock_llmrY   r   get_mock_callsr   )r   r   r   r   r   r   r   r   r   r   r   r   r   
structuredresultrY   s                   r   r   zLLMProvider.callE  s     T 	-,,,,,&5&A]]r
	<<<<
<<===( 	 	 	 	 	 	 	 	.33! /&;'' /' /+) 4        F  }&&777777d17;; L'+':'I'I'K'KD$3	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   A1B88
CCtools         >@autotool_choiceLLMToolCallResultc
                   K   ddl m}
  |
d| j         d| d           t          4 d{V  | j                            |||||||||		  	         d{V }| j        dk    r9d	d
lm} t          | j        |          r| j        	                                | _
        |cddd          d{V  S # 1 d{V swxY w Y   dS )a  
        Make an LLM API call with tool/function calling support.

        Args:
            messages: List of message dicts. Can include tool results with role='tool'.
            tools: List of tool definitions in OpenAI format.
            max_completion_tokens: Maximum tokens in response.
            temperature: Sampling temperature (0.0-2.0).
            scope: Scope identifier for tracking.
            max_retries: Maximum retry attempts.
            initial_backoff: Initial backoff time in seconds.
            max_backoff: Maximum backoff time in seconds.
            tool_choice: How to choose tools - "auto", "none", "required", or {"type": "function", "function": {"name": "..."}}

        Returns:
            LLMToolCallResult with content and/or tool_calls.
        r
   r   r   r   z+toolsN)	r   r   r   r   r   r   r   r   r   r3   r   r   )r   r   r>   r   r   call_with_toolsr   rY   r   r   r   )r   r   r   r   r   r   r   r   r   r   r   r   rY   s                r   r   zLLMProvider.call_with_tools  s     : 	-,,,,,	666666777( 	 	 	 	 	 	 	 	.>>!&;'' /'' ? 
 
 
 
 
 
 
 
F }&&777777d17;; L'+':'I'I'K'KD$/	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   A/B//
B9<B9fnc                     | j         dk    r7ddlm} t          | j        |          r| j                            |           dS dS dS )zISet a callback invoked on each call() instead of the fixed mock response.r3   r   r   N)r>   r   rY   r   r   set_response_callback)r   r   rY   s      r   r   z!LLMProvider.set_response_callback  se    =F""333333$-w77 >#99"=====	 #"> >r   responsec                     || _         | j        dk    r7ddlm} t	          | j        |          r| j                            |           dS dS dS )z+Set the response to return from mock calls.r3   r   r   N)r   r>   r   rY   r   r   set_mock_response)r   r   rY   s      r   r   zLLMProvider.set_mock_response  sr     '=F""333333$-w77 @#55h?????	 #"@ @r   c                     | j         dk    r4ddlm} t          | j        |          r| j                                        S | j        S )z$Get the list of recorded mock calls.r3   r   r   )r>   r   rY   r   r   r   r   r   rY   s     r   r   zLLMProvider.get_mock_calls  sV     =F""333333$-w77 <*99;;;r   c                     g | _         | j        dk    r6ddlm} t	          | j        |          r| j                                         dS dS dS )zClear the recorded mock calls.r3   r   r   N)r   r>   r   rY   r   r   clear_mock_callsr   s     r   r   zLLMProvider.clear_mock_calls  sm     =F""333333$-w77 7#4466666	 #"7 7r   c                    t          j                    dz  dz  }|                                st          d| d          t	          |          5 }t          j        |          }ddd           n# 1 swxY w Y   |                    d          }|dk    rt          d|           |                    d	i           }|                    d
          }|                    d          }|st          d          ||fS )a  
        Load OAuth credentials from ~/.codex/auth.json.

        Returns:
            Tuple of (access_token, account_id).

        Raises:
            FileNotFoundError: If auth file doesn't exist.
            ValueError: If auth file is invalid.
        z.codexz	auth.jsonzCodex auth file not found: z>
Run 'codex auth login' to authenticate with ChatGPT Plus/Pro.N	auth_modechatgptz#Expected auth_mode='chatgpt', got: tokensaccess_token
account_idzGNo access_token found in Codex auth file. Run 'codex auth login' again.)	r   homeexistsFileNotFoundErroropenr.   loadgetrq   )r   	auth_filefdatar   r   r   r   s           r   _load_codex_authzLLMProvider._load_codex_auth  sG    IKK(*[8	!! 	#xixxx   )__ 	 9Q<<D	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  HH[))		!!N9NNOOO(B''zz.11ZZ--
 	hfgggZ''s   A11A58A5c                 H   	 ddl }ddlm} |                    d                              |j                   |                    d                              |j                   t                              d           dS # t          $ r}t          d          |d}~ww xY w)z
        Verify that Claude Agent SDK can be imported and is properly configured.

        Raises:
            ImportError: If Claude Agent SDK is not installed.
            RuntimeError: If Claude Code is not authenticated.
        r   N)queryclaude_agent_sdkzclaude_agent_sdk._internalz&Claude Agent SDK imported successfullyz\Claude Agent SDK not installed. Run: uv add claude-agent-sdk or pip install claude-agent-sdk)	loggingr   r   	getLoggersetLevelWARNINGr   debugImportError)r   sdk_loggingr   es       r   _verify_claude_code_availablez)LLMProvider._verify_claude_code_available  s    	 *)))......!!"455>>{?RSSS!!">??HHI\]]]LLABBBBB 	 	 	n 	s   A>B 
B!BB!r_   ConfiguredLLMProviderc                 ,    t          | |j                  S )a  
        Return a configured wrapper for a specific bank operation.

        The wrapper applies per-bank overrides (e.g. Gemini safety settings)
        to every ``call()`` / ``call_with_tools()`` invocation without
        changing the underlying provider or its long-lived client connection.

        Args:
            config: Resolved ``HindsightConfig`` for the current bank/request.

        Returns:
            A ``ConfiguredLLMProvider`` that delegates to this provider with
            the supplied config applied.
        )r   r   )r   r_   s     r   with_configzLLMProvider.with_config-  s     %T6+LMMMr   c                 Z   K   | j         r!| j                                          d{V  dS dS )z3Clean up resources (e.g. stop llamacpp subprocess).N)r   cleanupr   s    r   r   zLLMProvider.cleanup>  sH       	0%--///////////	0 	0r   c           	         ddl m}m}m}m}m}m}m}m} t          j
        ||          }	t          j
        |d          }
|
st          |	          sn|
st          | d          t          j
        |d          }t          j
        ||          }t          j        t          j
        |d                    }t          j        t          j
        |d                    } | |	|
||d||          S )zECreate provider from environment variables using config.py constants.r
   )DEFAULT_LLM_MODELDEFAULT_LLM_PROVIDERENV_LLM_API_KEYENV_LLM_BASE_URLENV_LLM_DEFAULT_HEADERSENV_LLM_EXTRA_BODYENV_LLM_MODELENV_LLM_PROVIDERr   zV environment variable is required (unless using openai-codex, claude-code, or litellm)nullr}   )r>   rC   rD   rE   rF   rI   rJ   )r_   r   r   r   r   r   r   r   r   osgetenvrB   rq   r.   r/   )clsr   r   r   r   r   r   r   r   r>   rC   rD   rE   rI   rJ   s                  r   from_envzLLMProvider.from_envC  sY   		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 		
 9-/CDD)OR00 	/99 	 	"zzz   9-r22	-):;;Z	*<f E EFF
*RY/F%O%OPPs"!+
 
 
 	
r   )r}   NNNNNN)r   N)
NNNr   r   r   r   FFF)NNr   r   r   r   r   )r   r|   )r   r    r!   r"   strlistdictr   r   propertyr   r   r   intfloatboolr   r   r   r   r   r   tupler   r   r   r   classmethodr   r#   r   r   r|   r|   Q  s         !&(,*..2,0156:@( @(@( @( 	@(
 @( @( :@( !4Z@( !%t@( cNT)@( c3h$.@( #38nt3@( @( @( @(D     X      X 6 6 6 6 '+,0$(!$! %#"H HtCH~&H tH  #Tz	H
 T\H H H H H H H H 
H H H H\ -1$(!$!,28 8tCH~&8 DcN#8  #Tz	8
 T\8 8 8 8 8 4S>)8 
8 8 8 8t> > > > > >@# @$ @ @ @ @ T
        7 7 7 7!(%S/ !( !( !( !(F   6N# N*A N N N N"0 0 0 0
 $
 $
 $
 [$
 $
 $
r   r|   c                       e Zd ZdZdddedz  ddfdZdedefd	Zd
ee	eef                  dedefdZ
d
ee	eef                  dee	eef                  deddfdZdS )r   uH  
    Thin wrapper around LLMProvider that applies bank-specific config to every call.

    Obtained via ``LLMProvider.with_config(resolved_config)``.  The wrapper
    sets any provider-specific overrides (currently Gemini safety settings)
    immediately before each call using a ContextVar token, then resets it
    afterwards — so nesting is safe and the configuration cannot leak across
    operations.

    All attribute access falls through to the underlying provider so callers
    that read ``llm.provider``, ``llm.model``, etc. continue to work without
    any changes.
    r>   r|   rN   Nr   c                 v    t                               | d|           t                               | d|           d S )N	_provider_gemini_safety_settings)object__setattr__)r   r>   rN   s      r   r   zConfiguredLLMProvider.__init__z  s:    4h7774!:<RSSSSSr   namec                 T    t          t                              | d          |          S )Nr  )getattrr  __getattribute__)r   r  s     r   __getattr__z!ConfiguredLLMProvider.__getattr__  s"    v..t[AA4HHHr   r   kwargsc                 *  K   ddl m} |                    t                              | d                    }	 t                              | d          j        dd|i| d {V 	 |                    |           S # |                    |           w xY w)Nr   _safety_settings_ctxr  r  r   r#   )r   r  setr  r  r   reset)r   r   r  r  tokens        r   r   zConfiguredLLMProvider.call  s      >>>>>>$(()@)@G`)a)abb	.00{CCHeeRZe^deeeeeeeee &&u---- &&u----s   ,A; ;Br   r   c                 ,  K   ddl m} |                    t                              | d                    }	 t                              | d          j        d||d| d {V 	 |                    |           S # |                    |           w xY w)Nr   r  r  r  )r   r   r#   )r   r  r  r  r  r   r  )r   r   r   r  r  r  s         r   r   z%ConfiguredLLMProvider.call_with_tools  s       	?>>>>>$(()@)@G`)a)abb	.00{CCS ! 28         !&&u---- &&u----s   -A< <B)r   r    r!   r"   r  r   r   r   r  r  r   r   r#   r   r   r   r   k  s        T Tt TX\ T T T TI I I I I I
.4S#X#7 .3 .3 . . . ..tCH~&. DcN#. 	.
 
. . . . . .r   r   )	NNNNNNNNN)<r"   asyncior.   r   r   r   timeuuidpathlibr   typingr   r   rh   r   r   r   r   google.authgooglegoogle.oauth2r	   r   r   r_   r   r   r   r   r   metricsr   response_modelsr   DEFAULT_LLM_SEEDr   r   r   r   r   r  r   r   _llm_max_concurrent	Semaphorer   r   r   r   r2   	frozensetrA   r  rB   r  r  rz   r|   r   	LLMConfigr#   r   r   <module>r+     s       				 				                [ [ [ [ [ [ [ [ [ [ [ [------                 , + + + + + ' ' ' ' ' '  		8	$	$  '   # #GO 4 4 4 c)")$:CC@Z<[<[\\]] ))*=>> NcDj NS4Z N N N N,		 		 		 		 		 		 		 		!# !# !# !# !# !#H 'Y    ">s >t > > > > %)&*(,-1&*"& $*.26: ::: : 	:
 : Tz: t: S#X%: #s(^d*: t: 4Z: : !4K: sCx.4/: 	: : : :DW
 W
 W
 W
 W
 W
 W
 W
t2. 2. 2. 2. 2. 2. 2. 2.l 			s   A	 	AA