
    %j                         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mZ ddlZddlm	Z	 ddl
mZ ddlmZ  ej        e          ZdefdZ G d	 d
          Z	 	 	 	 	 	 	 	 	 	 ddededededee         dedee         dedededefdZdS )z
Server module for running Hindsight in a background thread.

Provides a simple way to start and stop the Hindsight HTTP API server
without blocking the main thread.
    N)Optional)Config)MemoryEngine)
create_appreturnc                     t          j         t           j        t           j                  5 } |                     d           |                     d           |                                 d         }ddd           n# 1 swxY w Y   |S )zFind a free port on localhost.) r      N)socketAF_INETSOCK_STREAMbindlistengetsockname)sports     X/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/hindsight/server.py_find_free_portr      s    	v~v'9	:	: "a	w	}}q!" " " " " " " " " " " " " " " Ks   AA;;A?A?c                       e Zd ZdZ	 	 	 	 	 	 	 	 	 dd
ededededee         dedee         dedefdZe	defd            Z
d Zddedd fdZd deddfdZd!dZd"dZdS )#Servera  
    Hindsight server that runs in a background thread.

    Example:
        ```python
        from hindsight import Server

        server = Server(
            db_url="pg0",
            llm_provider="groq",
            llm_api_key="your-api-key",
            llm_model="openai/gpt-oss-120b"
        )
        server.start()

        print(f"Server running at {server.url}")

        # Use the server...

        server.stop()
        ```
    pg0groqr	   openai/gpt-oss-120bN	127.0.0.1Finfodb_urlllm_providerllm_api_key	llm_modelllm_base_urlhostr   mcp_enabled	log_levelc
                 *   || _         || _        || _        || _        || _        || _        |pt                      | _        || _        |	| _	        d| _
        d| _        d| _        t          j                    | _        t          j                    | _        dS )aw  
        Initialize the Hindsight server.

        Args:
            db_url: Database URL. Use "pg0" for embedded PostgreSQL.
            llm_provider: LLM provider ("groq", "openai", "ollama", "gemini", "anthropic", "lmstudio")
            llm_api_key: API key for the LLM provider
            llm_model: Model name to use
            llm_base_url: Optional custom base URL for LLM API
            host: Host to bind to (default: 127.0.0.1)
            port: Port to bind to (default: auto-select free port)
            mcp_enabled: Whether to enable MCP server
            log_level: Uvicorn log level (default: warning)
        N)r   r   r   r   r    r!   r   r   r"   r#   _memory_server_thread	threadingEvent_started_stopped)
selfr   r   r   r   r    r!   r   r"   r#   s
             r   __init__zServer.__init__8   s    4 (&"(	-O--	&"/31537!))!))    r   c                 &    d| j          d| j         S )zGet the server URL.zhttp://:)r!   r   r,   s    r   urlz
Server.urlb   s     100TY000r.   c                    t          j                    }t          j        |           	 t          | j        | j        | j        | j        | j                  | _	        t          | j	        | j        d          }t          || j        | j        | j        d          }t!          j        |          | _        | j                                         |                    | j                                                   n0# t.          $ r#}t0                              d|             d}~ww xY w	 | j	        r,|                    | j	                                                   |                                 | j                                         dS # | j	        r,|                    | j	                                                   |                                 | j                                         w xY w)z&Run the server in a background thread.)r   memory_llm_providermemory_llm_api_keymemory_llm_modelmemory_llm_base_urlT)memorymcp_api_enabledinitialize_memoryasyncio)appr!   r   r#   loopzServer error: N)r;   new_event_loopset_event_loopr   r   r   r   r   r    r%   r   r"   r   r!   r   r#   uvicornr   r&   r*   setrun_until_completeserve	Exceptionloggererrorcloser+   )r,   r=   r<   configes        r   _run_serverzServer._run_serverg   s   %''t$$$)	 '{$($5#'#3!%$($5  DL | $ 0"&  C YY.  F #>&11DL M ##DL$6$6$8$89999 	 	 	LL-!--...	 : | >''(:(:(<(<===JJLLLM | >''(:(:(<(<===JJLLLMs+   CC9 8F 9
D&D!!D&&F A"G.      >@timeoutc                 L   | j         (| j                                         rt          d          | j                                         | j                                         t          j        | j        d          | _         | j         	                                 | j        
                    |           t          j                    }t          j                    |z
  |k     r	 t          j        | j        | j        fd          5  t                               d| j                    | cddd           S # 1 swxY w Y   n6# t&          t          j        t*          f$ r t          j        d           Y nw xY wt          j                    |z
  |k     t          d	| d
          )a  
        Start the server in a background thread.

        Args:
            timeout: Maximum time to wait for server to start (seconds)

        Returns:
            self (for chaining)

        Raises:
            RuntimeError: If server fails to start within timeout
        NzServer is already runningT)targetdaemonrL   r
   zHindsight server started at g?zServer failed to start within z seconds)r'   is_aliveRuntimeErrorr*   clearr+   r(   ThreadrJ   startwaittimer   create_connectionr!   r   rE   r   r2   ConnectionRefusedErrorrL   OSErrorsleep)r,   rL   
start_times      r   rU   zServer.start   s    <#(=(=(?(?#:;;; 't/?MMM 	7+++ Y[[
ikkJ&00 -ty$).DaPPP    KK Itx I IJJJ                                  +FNGD      
3  ikkJ&00 MGMMMNNNs6   $"E $D7*E 7D;;E >D;?E 0E65E6      $@c                 *   | j         dS d| j         _        | j        N| j                            |           | j                                        rt
                              d           d| _         d| _        t
                              d           dS )zx
        Stop the server.

        Args:
            timeout: Maximum time to wait for server to stop (seconds)
        NTrP   z"Server thread did not stop cleanlyzHindsight server stopped)r&   should_exitr'   joinrQ   rE   warningr   )r,   rL   s     r   stopzServer.stop   s     <F $(  <#Lg...|$$&& ECDDD./////r.   c                 *    |                                  S )zContext manager entry.)rU   r1   s    r   	__enter__zServer.__enter__   s    zz||r.   c                 .    |                                   dS )zContext manager exit.N)rb   )r,   exc_typeexc_valexc_tbs       r   __exit__zServer.__exit__   s    		r.   )	r   r   r	   r   Nr   NFr   )rK   )r]   )r   r   )r   N)__name__
__module____qualname____doc__strr   intboolr-   propertyr2   rJ   floatrU   rb   rd   ri    r.   r   r   r       sj        2 ".&*"!(* (*(* (* 	(*
 (* sm(* (* sm(* (* (* (* (* (*T 1S 1 1 1 X1.  .  . `#O #OU #Oh #O #O #O #OJ0 0E 0T 0 0 0 0.        r.   r   r   r   r	   r   r   Fra   rK   r   r   r   r   r    r!   r   r"   r#   rL   c
                 ^    t          | ||||||||	  	        }
|
                    |	          S )a  
    Start a Hindsight server in a background thread.

    This is a convenience function that creates and starts a Server instance.

    Args:
        db_url: Database URL. Use "pg0" for embedded PostgreSQL.
        llm_provider: LLM provider ("groq", "openai", "ollama", "gemini", "anthropic", "lmstudio")
        llm_api_key: API key for the LLM provider
        llm_model: Model name to use
        llm_base_url: Optional custom base URL for LLM API
        host: Host to bind to (default: 127.0.0.1)
        port: Port to bind to (default: auto-select free port)
        mcp_enabled: Whether to enable MCP server
        log_level: Uvicorn log level (default: warning)
        timeout: Maximum time to wait for server to start (seconds)

    Returns:
        Running Server instance

    Example:
        ```python
        from hindsight import start_server, Client

        server = start_server(
            db_url="pg0",
            llm_provider="groq",
            llm_api_key="your-api-key",
            llm_model="openai/gpt-oss-120b"
        )

        client = Client(base_url=server.url)
        client.put(agent_id="assistant", content="User likes Python")

        server.stop()
        ```
    )	r   r   r   r   r    r!   r   r"   r#   rP   )r   rU   )r   r   r   r   r    r!   r   r"   r#   rL   servers              r   start_serverrv      sJ    b !!
 
 
F <<<(((r.   )
r   r   r	   r   Nr   NFra   rK   )rm   r;   loggingr   r(   rW   typingr   r@   r   hindsight_apir   hindsight_api.apir   	getLoggerrj   rE   ro   r   r   rn   rp   rr   rv   rs   r.   r   <module>r|      s                         & & & & & & ( ( ( ( ( (		8	$	$    y y y y y y y yz *"&<) <)<)<) <) 	<)
 3-<) <) 3-<) <) <) <) <) <) <) <) <) <)r.   