
    'j4                        U d Z ddlZddlZddlZddlmZmZ ddlZddlm	Z	 ddl
mZmZmZmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ dZej                            dd          Zej                            dd          Zej                            dd          Z ej        dd          Z ej        e!         e"d<   ddZ# e#              G d de          Z$defde%de%de$fdZ& G d de          Z'dS ) a  Shared base for all Enterprise Brain agents.

By default agents use the gateway model string directly (no extra provider).
Pass ``api_base`` + optional ``api_key`` to route through a LiteLLM proxy instead.

``EnterpriseAgent`` subclasses ``PydanticAIResponder`` (pylogue), inheriting
streaming, tool-rendering, system-prompt management and conversation history
out of the box.  Callers can use it directly as a pylogue responder, or call
``agent.run(...)`` / ``agent.tool_plain(...)`` as before.
    N)AnyCallable)data_snapshot)ClauseContainsClauseEquals	ModelInfoProvider)Agent)OpenAIChatModel)LiteLLMProvider)OpenAIProvider)PydanticAIResponderzgateway/openai:gpt-5-miniLITELLM_PROVIDER_MODEL_NAMEzgemini/gemini-2.5-flash	MLX_MODEL MLX_BASE_URLzhttp://localhost:8080/v1_pylogue_activeF)defaultreturnc                     t           } |                     d          d                                         }t          j                    }d}|j        D ]"}|                    |          }|	|j        } n#|$ddl}|	                    d| d|  dd	           dS t          |
          }t          j                            dd          }t          dd|rt          j        |          ndt#          d          |t%          | ||          g          }	t          j        t          j        |	g|j        |j                             dS )u  Register a LiteLLM wrapper provider so genai-prices can cost custom deployments.

    LiteLLM deployments are typically named like ``"divami-gemini/gemini-2.5-flash"``,
    wrapping a well-known base model (``"gemini-2.5-flash"`` — the part after the last ``/``).
    This function:
      1. Strips the base model name from the deployment string.
      2. Looks it up in the bundled genai-prices database.
      3. Registers a custom provider (matched by ``provider_id="litellm"``) that
         claims any model name containing the base name and reuses its pricing.

    No prices are hardcoded — they are always pulled from the bundled data.
    /Nr   z8genai-prices: could not resolve pricing for base model 'z' (derived from 'z'). Cost will not be tracked.   )
stacklevel)containsLITELLM_API_BASEr   zlitellm-wrapperzLiteLLM Wrapperz(?!)litellm)equals)idmatchprices)r   nameapi_patternprovider_matchmodel_matchmodels)	providersfrom_auto_update)DEFAULT_LITELLM_MODEL_IDsplitlowerr   get_snapshotr'   
find_modelr!   warningswarnr   osenvirongetr	   reescaper   r   set_custom_snapshotDataSnapshotr(   )

deployment
base_modelsnapresolved_pricesprovidermodelr.   r%   api_baselitellm_providers
             :/var/www/html/ai-enterprise-brain/backend/chanakya/base.py_register_litellm_model_pricesr@   *   s    *J!!#&&r*0022J %''DON  ##J//#lOE  Hz H H(H H H 	 	
 	
 	

 	
 !*555Kz~~0"55H+3@BIh'''#9555!&  
    %"'9$.9!2	
 	
 	
        c                   "     e Zd ZdZ fdZ xZS )MLXChatModela  ``OpenAIChatModel`` variant for ``mlx_lm.server``.

    ``mlx_lm.server`` requires the system message to be strictly the *first*
    message in the list and rejects requests that have system messages scattered
    through conversation history (which pydantic-ai produces when message_history
    is used across turns).  This subclass post-processes the mapped messages to:
      1. Collect all ``role="system"`` messages.
      2. Keep only the last one (the most-current instructions).
      3. Hoist it to position 0.
    c                    K   t                                          ||           d {V }d |D             }d |D             }|r|d         g|S |S )Nc                 D    g | ]}|                     d           dk    |S rolesystemr2   .0ms     r?   
<listcomp>z.MLXChatModel._map_messages.<locals>.<listcomp>{   s,    OOOQQUU6]]h5N5Nq5N5N5NrA   c                 D    g | ]}|                     d           dk    |S rF   rI   rJ   s     r?   rM   z.MLXChatModel._map_messages.<locals>.<listcomp>|   s,    SSSv(9R9R19R9R9RrA   r   )super_map_messages)selfmessagesmodel_request_parametersopenai_messagessystem_msgsnon_system_msgs	__class__s         r?   rP   zMLXChatModel._map_messagesy   sy       % 5 5h@X Y YYYYYYYOO/OOOSSoSSS 	7O6o66rA   )__name__
__module____qualname____doc__rP   __classcell__rW   s   @r?   rC   rC   m   sB        	 	        rA   rC   z!mlx-community/Qwen3.5-9B-MLX-4bit
model_namebase_urlc                 @    t          | t          |                    S )a  Create an MLX-backed model via mlx_lm.server's OpenAI-compatible endpoint.
    
    Prerequisite: an instance of ``mlx_lm.server`` running and serving the desired model
    at the specified URL (default: ``http://localhost:8080/v1``).
    You can run it locally using `mlx_lm.server --model mlx-community/Qwen3.5-9B-MLX-4bit --host 0.0.0.0`
    once you `pip install mlx_lm`. The Qwen model will be automatically downloaded on first run if not present locally.
    )r_   )r^   r;   )rC   r   )r^   r_   s     r?   make_mlx_modelra      s#     :PX8Y8Y8YZZZZrA   c                       e Zd ZdZd!defdZd!def fdZedddeddddddddd	d
edededz  dedz  dedz  dededz  dedz  de	de
dededz  dedz  dedz  ddf fdZdedefdZdedefdZdedefdZde	de	fdZde	fd Z xZS )"EnterpriseAgentu  Pydantic-AI agent with LiteLLM routing and full pylogue responder support.

    Inherits from ``PydanticAIResponder``, so every instance is directly usable
    as a pylogue streaming responder (``await agent("prompt", context=ctx)``),
    with streaming, tool-rendering, system-prompt management, and conversation
    history all included.

    ``pylogue_instructions`` (mermaid/HTML hints) are injected **only** when the
    agent is invoked via the pylogue ``/chat`` WebSocket — i.e. when
    ``set_context()`` has been called by pylogue's session machinery.  REST API
    calls from ``/query`` and ``/query/stream`` bypass ``set_context`` entirely,
    so they receive a clean system prompt with no mermaid or HTML instructions.

    Args:
        instructions:       The agent's persona / system instructions.
        model_id:           Model identifier when NOT routing through LiteLLM
                            or MLX (default: ``"gateway/openai:gpt-5-mini"``).
        api_base:           When provided, requests are routed through the
                            LiteLLM proxy at this URL.
        api_key:            API key for the proxy; falls back to
                            ``LITELLM_API_KEY`` env var.
        mlx_model:          When provided (or ``MLX_MODEL`` env var is set),
                            requests are served by a local ``mlx_lm.server`` instance.
                            Takes precedence over ``model_id`` but not ``api_base``.
        mlx_base_url:       mlx_lm.server OpenAI-compatible endpoint; falls back to
                            ``MLX_BASE_URL`` env var or ``http://localhost:8080/v1``.
        logfire_env:        When provided, logfire is configured with this
                            environment name and pydantic-ai instrumentation
                            is enabled automatically.
        agent_deps:         Optional deps object forwarded to the underlying
                            pydantic_ai.Agent runs (passed to PydanticAIResponder).
        show_tool_details:  Whether to render full tool call/result details in
                            the stream (passed to PydanticAIResponder).
        retries:            Number of retries for the underlying agent.
    Nr   c           	          ddl m}m}  || j                            dd          t          | j                            dg                     |t                                          r|nd          S )aj  Inject pylogue instructions only during pylogue WebSocket sessions.

        ``_pylogue_active`` is a ContextVar set to ``True`` for the exact
        duration of ``__call__`` (the pylogue WS message handler). REST API calls
        via ``agent.run()`` never enter ``__call__``, so the var stays ``False``
        and they receive a clean system prompt.
        r   )PYLOGUE_INSTRUCTIONScompose_system_promptbase_promptr   
additional)rg   additional_instructionsuserpylogue_instructions)pylogue.integrations.commonre   rf   _prompt_stater2   listr   )rQ   rj   re   _csps       r?   _compose_system_promptz&EnterpriseAgent._compose_system_prompt   s    	
 	
 	
 	
 	
 	
 	
 	
 t*..}bAA$();)?)?b)Q)Q$R$R9H9L9L9N9N!V!5!5TV	
 
 
 	
rA   textc                  K   t                               d          }	 t                                          ||          2 3 d{V }|W V  6 	 t                               |           dS # t                               |           w xY w)a  Pylogue WebSocket message handler.

        Sets ``_pylogue_active`` for the exact duration of this call so that
        ``_compose_system_prompt`` injects pylogue instructions for WS sessions
        but not for REST API calls via ``agent.run()``.
        TN)r   setrO   __call__reset)rQ   rq   contexttokenchunkrW   s        r?   rt   zEnterpriseAgent.__call__   s        ##D))	)$ww//g>>       e  ?> !!%(((((O!!%((((s   "A, AA, ,BT   )model_idr=   api_key	mlx_modelmlx_base_urllogfire_envservice_name
agent_depsshow_tool_detailsretries	deps_typeoutput_typecapabilitiesinstructionsrz   r=   r{   r|   r}   r~   r   r   r   r   r   r   r   c                   |r*t          j        ||d           t          j                     |pt          x}rt	          ||          }n@|r<|pt          j        d          }t          t          t          ||                    }n|}t          |f||d|t          |          ni |t          |          ni |t          |	          ni }||	
 |            }	t                                          ||	|

           d S )NF)environmentr   	scrubbingLITELLM_API_KEY)r=   r{   )r;   )r   r   )r   )r   )r   )r   r   )logfire	configureinstrument_pydantic_aiDEFAULT_MLX_MODELra   r0   getenvr   r)   r   r
   dictrO   __init__)rQ   r   rz   r=   r{   r|   r}   r~   r   r   r   r   r   r   r   effective_mlxr<   resolved_keypydantic_agentrW   s                      r?   r   zEnterpriseAgent.__init__   sf   $  	-+L\abbbb*,,,&;*;<= 		"=,??EE 	"Bbi0A&B&BL#(((LQQQ  EE
 E
%
 
 -6,Ati((((r	

 1<0Gt,,,,R
 3?2Jt....PR
 
  Z%7"J 	JRcdddddrA   funcc                 6    | j                             |          S )z>Register a plain (no RunContext) tool on the underlying agent.)agent
tool_plainrQ   r   s     r?   r   zEnterpriseAgent.tool_plain  s    z$$T***rA   c                 6    | j                             |          S )z8Register a tool with RunContext on the underlying agent.)r   toolr   s     r?   r   zEnterpriseAgent.tool  s    zt$$$rA   c                 6    | j                             |          S )zBRegister a dynamic system-prompt function on the underlying agent.)r   system_promptr   s     r?   r   zEnterpriseAgent.system_prompt  s    z''---rA   argskwargsc                    K   |                     d| j                    | j        j        |i | d{V }|                                | _        |S )a3  Run the agent with automatic conversation-history threading.

        Passes ``self.message_history`` into the underlying ``Agent.run`` call
        (unless the caller supplies their own ``message_history`` kwarg) and
        updates it from the result, so successive ``run()`` calls share context.
        message_historyN)
setdefaultr   r   runall_messages)rQ   r   r   results       r?   r   zEnterpriseAgent.run  se       	+T-ABBB%tz~t6v66666666%2244rA   c                 &     | j         j        di |S )zDExpose the agent as an A2A ASGI app (delegates to ``Agent.to_a2a``). )r   to_a2a)rQ   r   s     r?   r   zEnterpriseAgent.to_a2a(  s     tz **6***rA   )N)rX   rY   rZ   r[   strrp   rt   DEFAULT_MODEL_IDDEFAULT_MLX_BASE_URLr   boolinttypern   r   r   r   r   r   r   r   r\   r]   s   @r?   rc   rc      s4       " "H
 
3 
 
 
 
&) )3 ) ) ) ) ) )& )#" $0"&#'"&!%#'$(!1e 1e 1e1e 	1e
 *1e t1e :1e 1e 4Z1e Dj1e 1e  1e 1e $;1e D[1e  Tk!1e" 
#1e 1e 1e 1e 1e 1ep+x +H + + + +% %h % % % %.( .x . . . .
s 
c 
 
 
 
+s + + + + + + + +rA   rc   )r   N)(r[   contextvarsr0   r3   typingr   r   r   genai_pricesr   genai_prices.typesr   r   r   r	   pydantic_air
   pydantic_ai.models.openair   pydantic_ai.providers.litellmr   pydantic_ai.providers.openair    pylogue.integrations.pydantic_air   r   r1   r2   r)   r   r   
ContextVarr   r   __annotations__r@   rC   r   ra   rc   r   rA   r?   <module>r      s<  	 	 	     				 				                  & & & & & & P P P P P P P P P P P P       5 5 5 5 5 5 9 9 9 9 9 9 7 7 7 7 7 7 @ @ @ @ @ @. :>>*GIbcc JNN;33 z~~n6PQQ  1G0Fu1 1 1'-   
= = = =@            ?   . :([ [[[ [ [ [ [Y+ Y+ Y+ Y+ Y+) Y+ Y+ Y+ Y+ Y+rA   