o
    ưiݡ                  
   @   s  d Z ddlZddlmZ ddlmZmZmZmZm	Z	 ddl
mZmZmZmZmZmZmZ ddlmZ ddlmZ ddlmZmZmZ dd	lmZ dd
lmZmZmZm Z m!Z!m"Z" ddl#m$Z$ e Z%de&de&fddZ'de&de(fddZ)dFde&dee( de&fddZ*de&dee&ef de&fddZ+dee! dee! fddZ,de&de(fddZ-de!fddZ.G dd  d eZ/G d!d" d"eZ0e%j1d#d$geeged%eefd&efd'd(Z2e%j1d)d$geeged%eefde&d&efd*d+Z3e%j1d,d$geeged%e%j1d-d$geeged%eefde&d&efd.d/Z4e%j5d0d$geegd1eefd2e/d&efd3d4Z6e%j7d,d$geegd1eefde&d2e/d&efd5d6Z8e%j9d,d$geegd1eefde&d&efd7d8Z:e%j;d,d$geegd1eefde&d2e0d&efd9d:Z<e%j5d;d$geegd1eefd2e$d<ed=ed&efd>d?Z=e%j5d@ddAgeegd1edBeefdCed&edee&ef fdDdEZ>dS )Gz
CRUD ENDPOINTS FOR PROMPTS
    N)Path)AnyDictListOptionalcast)	APIRouterDependsFileHTTPExceptionRequestResponse
UploadFile	BaseModel)verbose_proxy_logger)CommonProxyErrorsLitellmUserRolesUserAPIKeyAuth)user_api_key_auth)ListPromptsResponse
PromptInfoPromptInfoResponsePromptLiteLLMParams
PromptSpecPromptTemplateBase)TestPromptRequest	prompt_idreturnc                 C   s0   d| v r|  dd S d| v r|  dd S | S )a  
    Extract the base prompt ID by stripping the version suffix if present.

    Args:
        prompt_id: Prompt ID that may include version suffix (e.g., "jack_success.v1" or "jack_success_v1")

    Returns:
        Base prompt ID without version suffix (e.g., "jack_success")

    Examples:
        >>> get_base_prompt_id("jack_success.v1")
        "jack_success"
        >>> get_base_prompt_id("jack_success_v1")
        "jack_success"
        >>> get_base_prompt_id("jack_success")
        "jack_success"
    .vr   _v)splitr    r#   ]/home/app/Keep/.python/lib/python3.10/site-packages/litellm/proxy/prompts/prompt_endpoints.pyget_base_prompt_id$   s
   r%   c                 C   sn   d| v r|  dd }zt|W S  ty   Y nw d| v r5|  dd }zt|W S  ty4   Y dS w dS )a  
    Extract the version number from a versioned prompt ID.

    Args:
        prompt_id: Prompt ID that may include version suffix (e.g., "jack_success.v2" or "jack_success_v2")

    Returns:
        Version number (defaults to 1 if no version suffix or invalid format)

    Examples:
        >>> get_version_number("jack_success.v2")
        2
        >>> get_version_number("jack_success_v2")
        2
        >>> get_version_number("jack_success")
        1
    r      r    )r!   int
ValueError)r   version_strr#   r#   r$   get_version_number?   s    

r*   versionc                 C   s"   |du r| S t | }| d| S )aB  
    Construct a versioned prompt ID from a base prompt_id and version number.

    Args:
        prompt_id: Base prompt ID (e.g., "jack_success")
        version: Version number (if None, returns the base prompt_id unchanged)

    Returns:
        Versioned prompt ID (e.g., "jack_success.v4")

    Examples:
        >>> construct_versioned_prompt_id("jack_success", 4)
        "jack_success.v4"
        >>> construct_versioned_prompt_id("jack_success", None)
        "jack_success"
        >>> construct_versioned_prompt_id("jack_success.v2", 4)
        "jack_success.v4"
    Nr   )r%   )r   r+   base_idr#   r#   r$   construct_versioned_prompt_idd   s   r-   all_prompt_idsc                 C   sb   t | d}g }| D ]}t |d|kr t|d}|||f q|r/|jdd |d d S | S )a  
    Find the latest version of a prompt from available prompt IDs.

    Args:
        prompt_id: Base prompt ID or versioned prompt ID (e.g., "jack_success" or "jack_success.v2")
        all_prompt_ids: Dictionary of all available prompt IDs (keys are prompt IDs)

    Returns:
        The prompt ID with the highest version number, or the original prompt_id if no versions exist

    Examples:
        >>> all_ids = {"jack.v1": {}, "jack.v2": {}, "jack.v3": {}}
        >>> get_latest_version_prompt_id("jack", all_ids)
        "jack.v3"
        >>> get_latest_version_prompt_id("jack.v1", all_ids)
        "jack.v3"
        >>> all_ids = {"simple": {}}
        >>> get_latest_version_prompt_id("simple", all_ids)
        "simple"
    r"   T)reverser   r&   )r%   keysr*   appendsort)r   r.   r,   Zmatching_versionsZstored_prompt_idZversion_numr#   r#   r$   get_latest_version_prompt_id   s   

r3   promptsc                 C   sd   i }| D ]'}t |jd}t|jd}||vr|||< qt|| jd}||kr+|||< qt| S )z
    Filter a list of prompts to return only the latest version of each unique prompt.

    Args:
        prompts: List of PromptSpec objects

    Returns:
        List of PromptSpec objects with only the latest version of each prompt
    r"   )r%   r   r*   listvalues)r4   latest_promptspromptr,   r+   Zexisting_versionr#   r#   r$   get_latest_prompt_versions   s   

r9   c                    s>   | j jjd|idI dH }|rtdd |D }|d S dS )z
    Get the next version number for a prompt.

    Args:
        prisma_client: Prisma database client
        prompt_id: Base prompt ID

    Returns:
        Next version number (1 if no versions exist, max_version + 1 otherwise)
    r   whereNc                 s   s    | ]}|j V  qd S Nr+   ).0pr#   r#   r$   	<genexpr>   s    z.get_next_version_for_prompt.<locals>.<genexpr>r&   )dblitellm_prompttable	find_manymax)prisma_clientr   existing_promptsZmax_versionr#   r#   r$   get_next_version_for_prompt   s   rG   c                 C   s   ddl }ddlm} |  }|d }|dd}|d}t|tr'||}|di |}|d}|rGt|tr?||}tdi |}	ntd	d
}	| d| }
t	|
||	|d|ddS )z
    Helper function to create a PromptSpec with versioned prompt_id from a DB prompt entry.

    Args:
        db_prompt: The DB prompt object (from prisma)

    Returns:
        PromptSpec with versioned prompt_id (e.g., "chat_prompt.v1")
    r   N)r   r   r+   r&   litellm_paramsprompt_inforA   prompt_typer   
created_at
updated_atr   rH   rI   rL   rM   r#   )
json"litellm.types.prompts.init_promptsr   
model_dumpget
isinstancestrloadsr   r   )	db_promptrO   r   Zprompt_dictbase_prompt_idr+   Zlitellm_params_datarH   Zprompt_info_datarI   Zversioned_prompt_idr#   r#   r$   create_versioned_prompt_spec   s.   







rX   c                   @   s.   e Zd ZU eed< eed< dZee ed< dS )Promptr   rH   NrI   )	__name__
__module____qualname__rT   __annotations__r   rI   r   r   r#   r#   r#   r$   rY     s   
 rY   c                   @   s.   e Zd ZU dZee ed< dZee ed< dS )PatchPromptRequestNrH   rI   )	rZ   r[   r\   rH   r   r   r]   rI   r   r#   r#   r#   r$   r^     s   
 r^   z/prompts/listzPrompt Management)tagsdependenciesZresponse_modeluser_api_key_dictc                    s,  ddl m} ddlm} | j}|durQtttt  |	dd}|durQg }|D ]"}||j
v rK|j
| }tt|jd|j|j|j|jd}|| q)t|dS | jdur| j|jksc| j|jjkrt|j
 }	t|	d}
g }|
D ]}tt|jd|j|j|j|jd}|| qst|dS tg dS )	ud  
    List the prompts that are available on the proxy server

    👉 [Prompt docs](https://docs.litellm.ai/docs/proxy/prompt_management)

    Example Request:
    ```bash
    curl -X GET "http://localhost:4000/prompts/list" -H "Authorization: Bearer <your_api_key>"
    ```

    Example Response:
    ```json
    {
        "prompts": [
            {
                "prompt_id": "my_prompt_id",
                "litellm_params": {
                    "prompt_id": "my_prompt_id",
                    "prompt_integration": "dotprompt",
                    "prompt_directory": "/path/to/prompts"
                },
                "prompt_info": {
                    "prompt_type": "config"
                },
                "created_at": "2023-11-09T12:34:56.789Z",
                "updated_at": "2023-11-09T12:34:56.789Z"
            }
        ]
    }
    ```
    r   )r   IN_MEMORY_PROMPT_REGISTRYNr4   r"   rN   r4   )litellm.proxy._typesr   %litellm.proxy.prompts.prompt_registryrc   metadatar   r   r   rT   rR   IN_MEMORY_PROMPTSr   r%   r   rH   rI   rL   rM   r1   r   	user_rolePROXY_ADMINvaluer5   r6   r9   )ra   r   rc   Zkey_metadatar4   Zprompt_listr   Zoriginal_promptZprompt_copyall_promptsr7   Zprompts_for_displayr#   r#   r$   list_prompts  sT   (

	





rm   z/prompts/{prompt_id}/versionsc           	   	      s   ddl m} |jdu s|jtjkr|jtjjkrtdddt| d t|j	
 } fdd	|D }|s?td
d  dg }|D ]!}t|jd}t|jd t |j|j|j|j|d}|| qC|jdd dd t|dS )u  
    Get all versions of a specific prompt by base prompt ID
    
    👉 [Prompt docs](https://docs.litellm.ai/docs/proxy/prompt_management)
    
    Example Request:
    ```bash
    curl -X GET "http://localhost:4000/prompts/jack_success/versions" \
        -H "Authorization: Bearer <your_api_key>"
    ```
    
    Example Response:
    ```json
    {
        "prompts": [
            {
                "prompt_id": "jack_success.v1",
                "litellm_params": {...},
                "prompt_info": {"prompt_type": "db"},
                "created_at": "2023-11-09T12:34:56.789Z",
                "updated_at": "2023-11-09T12:34:56.789Z"
            },
            {
                "prompt_id": "jack_success.v2",
                "litellm_params": {...},
                "prompt_info": {"prompt_type": "db"},
                "created_at": "2023-11-09T13:45:12.345Z",
                "updated_at": "2023-11-09T13:45:12.345Z"
            }
        ]
    }
    ```
    r   rb   N  z*Only proxy admins can view prompt versionsstatus_codedetailr"   c                    s    g | ]}t |jd  kr|qS )r"   )r%   r   )r>   r8   rW   r#   r$   
<listcomp>  s
    z'get_prompt_versions.<locals>.<listcomp>  z No versions found for prompt ID r   rH   rI   rL   rM   r+   c                 S   s
   | j pdS )Nr&   r=   )r?   r#   r#   r$   <lambda>  s   
 z%get_prompt_versions.<locals>.<lambda>T)keyr/   rd   )rf   rc   ri   r   rj   rk   r   r%   r5   rh   r6   r*   r   r   rH   rI   rL   rM   r1   r2   r   )	r   ra   rc   rl   Zprompt_versionsZversioned_promptsr8   version_numberZversioned_promptr#   rr   r$   get_prompt_versionsk  s@   +




ry   z/prompts/{prompt_id}z/prompts/{prompt_id}/infoc                    s  ddl m} d}|jdur.tttt  |jdd}|dur.| |vr.tdd|  dd|j	durA|j	t
jks@|j	t
jjkrAntd	d
|j	 d| d|| }|du rct| |jd}||}|du rqtdd|  ddt|jd}tt|jd|j|j|j|j|d}d}zD||j}	|	dur|	j}
|
dkrddlm} t|	|r|	j }|durt|dkrt |! d }t"||| d || d d}W n	 t#y   Y nw t$||dS )uT  
    Get detailed information about a specific prompt by ID, including prompt content

    👉 [Prompt docs](https://docs.litellm.ai/docs/proxy/prompt_management)

    Example Request:
    ```bash
    curl -X GET "http://localhost:4000/prompts/my_prompt_id/info" \
        -H "Authorization: Bearer <your_api_key>"
    ```

    Example Response:
    ```json
    {
        "prompt_id": "my_prompt_id",
        "litellm_params": {
            "prompt_id": "my_prompt_id",
            "prompt_integration": "dotprompt",
            "prompt_directory": "/path/to/prompts"
        },
        "prompt_info": {
            "prompt_type": "config"
        },
        "created_at": "2023-11-09T12:34:56.789Z",
        "updated_at": "2023-11-09T12:34:56.789Z",
        "content": "System: You are a helpful assistant.

User: {{user_message}}"
    }
    ```
    r   rb   Nr4     Prompt 
 not foundro   rn   z:You are not authorized to access this prompt. Your role - z, Your key's prompts - r   r.   r"   ru   Z	dotpromptDotpromptManagerr&   contentrg   )Zlitellm_prompt_idr   rg   )prompt_specZraw_prompt_template)%rf   rc   rg   r   r   r   rT   rR   r   ri   r   rj   rk   get_prompt_by_idr3   rh   r*   r   r   r%   rH   rI   rL   rM   Zget_prompt_callback_by_idintegration_name0litellm.integrations.dotprompt.dotprompt_managerr   rS   prompt_managerZget_all_prompts_as_jsonlenr5   r0   r   	Exceptionr   )r   ra   rc   r4   r   latest_prompt_idrx   Zprompt_spec_responseZprompt_templateZprompt_callbackr   r   templatetemplate_idr#   r#   r$   get_prompt_info  sz   -









r   z/prompts)r_   r`   requestc           	   
      s$  ddl m} ddlm} |jdu s|jtjkr%|jtjjkr%tddd|du r1tdt	j
jdzDt|| jd	I dH }|jjj| j|| j | jrO| j ntd
d ddI dH }t|d}|j|dd}|du rstddd|W S  ty } ztd|  tdt|dd}~ww )uG  
    Create a new prompt

    👉 [Prompt docs](https://docs.litellm.ai/docs/proxy/prompt_management)

    Example Request:
    ```bash
    curl -X POST "http://localhost:4000/prompts" \
        -H "Authorization: Bearer <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
            "prompt_id": "my_prompt",
            "litellm_params": {
                "prompt_id": "json_prompt",
                "prompt_integration": "dotprompt",
                ### EITHER prompt_directory OR prompt_data MUST BE PROVIDED
                "prompt_directory": "/path/to/dotprompt/folder",
                "prompt_data": {"json_prompt": {"content": "This is a prompt", "metadata": {"model": "gpt-4"}}}
            },
            "prompt_info": {
                "prompt_type": "config"
            }
        }'
    ```
    r   rb   rE   Nrn   z$Only proxy admins can create promptsro     rE   r   rA   rJ   r   r+   rH   rI   datarV   r8   Zconfig_file_pathzFailed to initialize promptzError creating prompt: )rf   rc   litellm.proxy.proxy_serverrE   ri   r   rj   rk   r   r   db_not_connected_errorrG   r   rA   rB   createrH   model_dump_jsonrI   r   rX   initialize_promptr   r   	exceptionrT   )	r   ra   rc   rE   new_versionprompt_db_entryr   initialized_prompter#   r#   r$   create_promptO  sL   #

r   c              
      s  ddl m} ddlm} |jdu s|jtjkr%|jtjjkr%tddd|du r1tdt	j
jdzst| d	}|jjjd
|idI dH }|sPtdd| dd|| }|rc|jjdkrctdddt||dI dH }|jjj|||j |jr~|j ntdd ddI dH }	t|	d}
|j|
dd}|du rtddd|W S  ty } z|d}~w ty } ztd|  tdt|dd}~ww )u  
    Update an existing prompt

    👉 [Prompt docs](https://docs.litellm.ai/docs/proxy/prompt_management)

    Example Request:
    ```bash
    curl -X PUT "http://localhost:4000/prompts/my_prompt_id" \
        -H "Authorization: Bearer <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
            "prompt_id": "my_prompt",
            "litellm_params": {
                "prompt_id": "my_prompt",
                    "prompt_integration": "dotprompt",
                    "prompt_directory": "/path/to/prompts"
                },
                "prompt_info": {
                    "prompt_type": "config"
                }
            }
        }'
    ```
    r   rb   r   Nrn   z$Only proxy admins can update promptsro   r   r"   r   r:   rt   Prompt with ID r|   configrz   Cannot update config prompts.r   rA   rJ   r   r   r   r   zFailed to update promptzError updating prompt: )rf   rc   r   rE   ri   r   rj   rk   r   r   r   r%   rA   rB   rC   r   rI   rK   rG   r   rH   r   r   rX   r   r   r   r   rT   )r   r   ra   rc   rE   rW   rF   Zexisting_in_memoryr   r   r   r   r   r#   r#   r$   update_prompt  sr   "



r   c              
      sX  ddl m} ddlm} |jdu s|jtjkr%|jtjjkr%tddd|du r1tdt	j
jdzQ|| }|du rIt| |jd	}||}|} |du rWtd
d|  dd|jjdkrctdddt| d}|jjjd|idI dH  || dd| diW S  ty } z|d}~w ty } ztd|  tdt|dd}~ww )uz  
    Delete a prompt

    👉 [Prompt docs](https://docs.litellm.ai/docs/proxy/prompt_management)

    Example Request:
    ```bash
    curl -X DELETE "http://localhost:4000/prompts/my_prompt_id" \
        -H "Authorization: Bearer <your_api_key>"
    ```

    Example Response:
    ```json
    {
        "message": "Prompt my_prompt_id deleted successfully"
    }
    ```
    r   rb   r   Nrn   z$Only proxy admins can delete promptsro   r   r}   rt   r   r|   r   rz   zCannot delete config prompts.r"   r   r:   messager{   z deleted successfullyzError deleting prompt: )rf   rc   r   rE   ri   r   rj   rk   r   r   r   r   r3   rh   rI   rK   r%   rA   rB   Zdelete_manyZdelete_prompts_by_base_idr   r   r   rT   )r   ra   rc   rE   existing_promptr   rW   r   r#   r#   r$   delete_prompt  s^   



r   c              
      s  ddl m} ddlm} |jdu s|jtjkr%|jtjjkr%tddd|du r1tdt	j
jdz~|| }|du rEtd	d
|  dd|jjdkrQtddd|jdurY|jn|j}|jdurd|jn|j}|du rqtddd|jjjd| i| | ddI dH }tdi | }	|j| = | |jv r|j| = |j|	dd}
|
du rtddd|
W S  ty } z|d}~w ty } ztd|  tdt|dd}~ww )u  
    Partially update an existing prompt

    👉 [Prompt docs](https://docs.litellm.ai/docs/proxy/prompt_management)

    This endpoint allows updating specific fields of a prompt without sending the entire object.
    Only the following fields can be updated:
    - litellm_params: LiteLLM parameters for the prompt
    - prompt_info: Additional information about the prompt

    Example Request:
    ```bash
    curl -X PATCH "http://localhost:4000/prompts/my_prompt_id" \
        -H "Authorization: Bearer <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
            "prompt_info": {
                "prompt_type": "db"
            }
        }'
    ```
    r   rb   r   Nrn   z#Only proxy admins can patch promptsro   r   rt   r   r|   r   rz   r   zlitellm_params cannot be Noner   )rH   rI   )r;   r   r   zFailed to patch promptzError patching prompt: r#   )rf   rc   r   rE   ri   r   rj   rk   r   r   r   r   rI   rK   rH   rA   rB   updater   r   rQ   rh   Zprompt_id_to_custom_promptr   r   r   r   rT   )r   r   ra   rc   rE   r   Zupdated_litellm_paramsZupdated_prompt_infoZupdated_prompt_db_entryZupdated_prompt_specr   r   r#   r#   r$   patch_promptw  st   !




r   z/prompts/testfastapi_requestfastapi_responsec           #   
      s$  ddl m} ddlm} ddlm}m} ddlm} ddl	m
}	m}
m}m}m}m}m}m}m}m}m} z| }|j| jd\}}|||dd	}|jsRtd
dd| jpVi }|j|jd*i |}| }|j|d}|sttd
dd| jrdd |D }|| j }n|}|j  }d|d< |j|d}|!| ||d} | j"d*i d|d|d|ddd|d|
d|	d|d|dd d!|d"|d#|d$|d%|d&|I d H }!t#|!|r|!j$ddd'W S |!W S  ty }" z|"d }"~"w t%y }" zt&'d(|"  td)t(|"dd }"~"ww )+u  
    Test a prompt by rendering it with variables and executing an LLM call.
    
    This endpoint allows testing prompts before saving them to the database.
    The response is always streamed.
    
    👉 [Prompt docs](https://docs.litellm.ai/docs/proxy/prompt_management)
    
    Example Request:
    ```bash
    curl -X POST "http://localhost:4000/prompts/test" \
        -H "Authorization: Bearer <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
            "dotprompt_content": "---\nmodel: gpt-4o\ntemperature: 0.7\n---\n\nUser: Hello {{name}}",
            "prompt_variables": {
                "name": "World"
            }
        }'
    ```
    r   r   r~   )PromptManagerPromptTemplate)ProxyBaseLLMRequestProcessing)general_settings
llm_routerproxy_configproxy_logging_objselect_data_generatoruser_api_baseuser_max_tokens
user_modeluser_request_timeoutuser_temperaturer+   )r   test_prompt)r   rg   r   rz   z'Model is required in dotprompt metadataro   )rendered_contentz$No messages found in rendered promptc                 S   s   g | ]}| d dkr|qS )Zrolesystem)rR   )r>   msgr#   r#   r$   rs   E  s    ztest_prompt.<locals>.<listcomp>Tstream)modelmessagesr   r   r   ra   Z
route_typeZacompletionr   r   r   r   r   r   Nr   r   r   r   r   r+   )Zexclude_noneZexclude_unsetzError testing prompt: r   r#   ))pydanticr   r   r   -litellm.integrations.dotprompt.prompt_managerr   r   Z'litellm.proxy.common_request_processingr   r   r   r   r   r   r   r   r   r   r   r   r+   Z_parse_frontmatterZdotprompt_contentr   r   Zprompt_variablesZ	jinja_envZfrom_stringrenderZ_convert_to_messagesZconversation_historyoptional_paramscopyr   Zbase_process_llm_requestrS   rQ   r   r   r   rT   )#r   r   r   ra   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r+   r   ZfrontmatterZtemplate_contentr   	variablesr   Zdotprompt_managerZrendered_messagesZsystem_messagesr   r   r   Zbase_llm_response_processorresultr   r#   r#   r$   r     s    4





	


r   z/utils/dotprompt_json_converterutils.filec           	         s"  ddl m} | jr| jdstdddd}z[zC|  I dH }tt | j }|	| | }|
|}|j}||dW W |r[| r\|  z|j  W S  tyZ   Y S w S S  tys } ztd	d
t| dd}~ww |r| r|  z|j  W w  ty   Y w w w w )a  
    Convert a .prompt file to JSON format.

    This endpoint accepts a .prompt file upload and returns the equivalent JSON representation
    that can be stored in a database or used programmatically.

    Returns the JSON structure with 'content' and 'metadata' fields.
    r   )r   z.promptrz   z File must have .prompt extensionro   N)r   	json_datar   zError converting prompt file: )r   r   filenameendswithr   readr   tempfilemkdtempwrite_bytesZprompt_file_to_jsonstemexistsunlinkparentrmdirOSErrorr   rT   )	r   ra   r   Ztemp_file_pathZfile_contentr   r   r   r   r#   r#   r$   convert_prompt_file_to_json{  sJ   

r   r<   )?__doc__r   pathlibr   typingr   r   r   r   r   Zfastapir   r	   r
   r   r   r   r   r   r   Zlitellm._loggingr   re   r   r   r   Z$litellm.proxy.auth.user_api_key_authr   rP   r   r   r   r   r   r   Z$litellm.types.proxy.prompt_endpointsr   ZrouterrT   r%   r'   r*   r-   r3   r9   rG   rX   rY   r^   rR   rm   ry   r   postr   putr   deleter   patchr   r   r   r#   r#   r#   r$   <module>   s   $	 %'-T[wUnVm	 
