Ë
    uPêj•*  ã                  ót  — U d Z ddlmZ ddlmZ ddlmZ ddlmZm	Z	 ddl
Z
ddlmZmZmZmZ ddlmZ dd	lmZmZmZ dd
lmZ erddlmZ dZded<    G d„ de«      Z G d„ de«      Z G d„ de«      Z G d„ de«      Z  ee!e"df   «      Z#ded<    ei «      Z$ded<   d!d„Z% G d„ de«      Z&d"d„Z'd#d„Z(d$d „Z)y)%z…
Calls Nimble's /v2/search endpoint to search the web.

Nimble API Reference: https://docs.nimbleway.com/api-reference/search/search
é    )Úannotations)ÚMapping)ÚMappingProxyType)ÚTYPE_CHECKINGÚFinalN)Ú	BaseModelÚ
ConfigDictÚTypeAdapterÚValidationError)ÚBaseLLMException)ÚBaseSearchConfigÚSearchResponseÚSearchResult)Úget_secret_str)ÚLoggingz6https://docs.nimbleway.com/api-reference/search/searchr   Ú_NIMBLE_DOCS_URLc                  ól   — e Zd ZU dZ edd¬«      ZdZded<   dZded<   dZ	ded	<   dZ
ded
<   dZded<   y)Ú_NimbleResultz›One entry of Nimble's `results` array. Every field is optional so a single degraded
    result degrades to empty strings instead of failing the whole call.ÚignoreT©ÚextraÚfrozenNú
str | NoneÚtitleÚurlÚcontentÚdescriptionÚobjectÚadditional_data)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r	   Úmodel_configr   Ú__annotations__r   r   r   r   © ó    ún/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/llms/nimble/search/transformation.pyr   r      sH   … ñKñ  H°TÔ:€Là€Eˆ:ÓØ€CˆÓØ€GˆZÓØ"€K�Ó"à"€O�VÔ"r'   r   c                  ó0   — e Zd ZU dZ edd¬«      Zded<   y)Ú_NimbleSearchResponsez&Nimble's /v2/search response envelope.r   Tr   ztuple[_NimbleResult, ...]ÚresultsN)r    r!   r"   r#   r	   r$   r%   r&   r'   r(   r*   r*   ,   s   … Ù0á H°TÔ:€Lð 'Ô&r'   r*   c                  ó4   — e Zd ZU dZ edd¬«      ZdZded<   y)Ú_AdditionalDatazPThe slice of a result's free-form `additional_data` that maps onto SearchResult.r   Tr   Nr   Úpublish_date)r    r!   r"   r#   r	   r$   r.   r%   r&   r'   r(   r-   r-   6   s   … ÙZá H°TÔ:€Là#€L�*Ô#r'   r-   c                  óB   — e Zd ZU dZ edd¬«      ZdZded<   dZded<   y)	Ú_ErrorEnvelopezŠNimble reports errors as either `{"detail": ...}` (validation) or
    `{"success": "false", "task_id": ..., "message": ...}` (collection).r   Tr   Nr   ÚdetailÚmessage)	r    r!   r"   r#   r	   r$   r1   r%   r2   r&   r'   r(   r0   r0   >   s*   … ñLñ  H°TÔ:€Là€FˆJÓØ€GˆZÔr'   r0   .Ú_DomainListAdapterzFinal[Mapping[str, object]]Ú_NOTHINGc                ó,   — |�t        | |i«      S t        S )zRA one-entry mapping to spread into a payload, or nothing when the value is absent.)r   r4   )ÚkeyÚvalues     r(   Ú	_optionalr8   M   s   € à-2Ð->Ô˜S %˜LÓ)ÐLÄHÐLr'   c                  ó¨   — e Zd ZdZed	d„«       Z	 	 d
	 	 	 	 	 	 	 	 	 dd„Z	 d	 	 	 	 	 	 	 	 	 dd„Z	 	 	 	 	 	 	 	 dd„Z	 	 	 	 	 	 	 	 dd„Z		 	 	 	 	 	 	 	 dd„Z
y)ÚNimbleSearchConfigzhttps://sdk.nimbleway.com/v2c                  ó   — y)NÚNimbler&   r&   r'   r(   Úui_friendly_namez#NimbleSearchConfig.ui_friendly_nameU   s   € àr'   Nc                óv   — | j                  ||dd| j                  ¬«      }|st        d«      ‚i |¥d|› �dddœ¥S )	zô
        Validate environment and return headers.

        Returns a new dict rather than mutating ``headers``: the http handler calls this
        a second time after ``litellm/search/main.py`` already did, so it has to be idempotent.
        )ÚNIMBLE_API_KEYÚNIMBLE_API_BASE)Úcaller_api_keyÚcaller_api_baseÚkey_env_varsÚbase_env_varÚdefault_api_basezENIMBLE_API_KEY is not set. Set `NIMBLE_API_KEY` environment variable.zBearer zapplication/jsonÚlitellm)ÚAuthorizationzContent-TypezX-Client-Source)Úresolve_server_api_keyr@   Ú
ValueError)ÚselfÚheadersÚapi_keyÚapi_baseÚkwargsÚresolved_api_keys         r(   Úvalidate_environmentz'NimbleSearchConfig.validate_environmentY   si   € ð #'×"=Ñ"=Ø"Ø$Ø,Ø*Ø!×1Ñ1ð #>ó #
Ðñ  ÜÐdÓeÐeð
Øð
à&Ð'7Ð&8Ð9Ø.à(ò
ð 	
r'   c                óŠ   — |xs t        d«      xs | j                  j                  d«      }|j                  d«      r|S |› d�S )Nr@   ú/z/search)r   r@   ÚrstripÚendswith)rJ   rM   Úoptional_paramsÚdatarN   Úresolved_bases         r(   Úget_complete_urlz#NimbleSearchConfig.get_complete_urlw   sM   € ð !)Ò e¬NÐ;LÓ,MÒ eÐQU×QeÑQe×mÑmÐnqÓrˆØ×!Ñ! )Ô,Ø Ð Ø� Ð(Ð(r'   c                óÒ  — | j                  «       }|j                  d«      }t        |j                  «       D ��ci c]  \  }}||vsŒ||“Œ c}}«      }i t	        |j                  d«      «      ¥|¥dt        |t        «      rdj                  |«      n|i¥t        d|j                  d«      «      ¥t        dt        |t        «      r|j                  «       «      ¥S d«      ¥S c c}}w )aØ  
        Transform Search request to Nimble API format.

        Nimble already uses the Perplexity unified spec's names, so this is close to a pass-through:
        - query -> query (a list is joined with spaces; Nimble takes a single string)
        - max_results -> max_results (sent unclamped so Nimble's own 1-100 validation reports the error)
        - country -> country, upper-cased to the ISO form Nimble documents
        - search_domain_filter -> include_domains, with `-`-prefixed entries going to exclude_domains
        - max_tokens_per_page -> dropped (no Nimble equivalent)

        Everything else is forwarded as-is, so the rest of Nimble's surface stays reachable
        without LiteLLM tracking it.
        ÚcountryÚsearch_domain_filterÚqueryú Úmax_resultsN)Ú(get_supported_perplexity_optional_paramsÚgetr   ÚitemsÚ_domain_filtersÚ
isinstanceÚlistÚjoinr8   ÚstrÚupper)	rJ   r\   rU   rN   Úunified_paramsrZ   Úparamr7   Úpassthroughs	            r(   Útransform_search_requestz+NimbleSearchConfig.transform_search_requestƒ   sõ   € ð& !%× MÑ MÓ OˆØ(×,Ñ,¨YÓ7ˆô .Ø.=×.CÑ.CÓ.E×e™l˜e UÈÐVdÒIdˆU�E‰\Óeó
ˆð
Ü˜o×1Ñ1Ð2HÓIÓJð
àð
ð ¬
°5¼$Ô(?�S—X‘X˜e”_ÀUñ
ô ˜ ×':Ñ':¸=Ó'IÓJð	
ô
 ˜	´jÀÌ#Ô6N 7§=¡=£?ÓYð
ð 	
ð
 UYÓYð
ð 	
ùó fs   ºC#
ÁC#
c                óü  — 	 t         j                  |j                  «      }t        |j                  D �cg c]r  }t        d	|j                  xs d|j                  xs d|j                  xs |j                  xs dt        |j                  «      ddœt!        d|j                  «      ¤Ž‘Œt c}d¬«      S # t        $ r9}| j	                  d|› �|j
                  t        |j                  «      ¬«      ‚d}~ww xY wc c}w )
aÏ  
        Transform Nimble API response to LiteLLM unified SearchResponse format.

        `date` carries only the absolute `publish_date`. News results often carry a relative
        `publish_date_raw` ("1 day ago") instead, which is not a date, so the whole
        `additional_data` object rides through as an extra on `SearchResult` and nothing is lost.

        Nimble ranks results itself via metadata.position, so the order is preserved as received.
        A body that does not match the documented schema raises an attributed error rather than
        being reported as a successful empty search. Parsing the response bytes rather than
        `.json()` covers the non-JSON case through that same path.
        z:response does not match the documented /v2/search schema: )Úerror_messageÚstatus_coderK   NÚ )r   r   ÚsnippetÚdateÚlast_updatedr   Úsearch)r+   r   r&   )r*   Úmodel_validate_jsonr   r   Úget_error_classrn   ÚdictrK   r   r+   r   r   r   r   Ú_publish_dater   r8   )rJ   Úraw_responseÚlogging_objrN   ÚparsedÚeÚresults          r(   Útransform_search_responsez,NimbleSearchConfig.transform_search_response§   s  € ð$	Ü1×EÑEÀl×FZÑFZÓ[ˆFô ð %Ÿn™nö
ð ô ð Ø Ÿ,™,Ò,¨"ØŸ
™
Ò( bØ"ŸN™NÒF¨f×.@Ñ.@ÒFÀBÜ& v×'=Ñ'=Ó>Ø!%ñô  Ð 1°6×3IÑ3IÓJóò
ð ô
ð 	
øô ò 	Ø×&Ñ&Ø ZÐ[\ÐZ]Ð^Ø(×4Ñ4Ü˜\×1Ñ1Ó2ð 'ó ð ûð	üò
s   ‚B4 ´A7C9Â4	C6Â=4C1Ã1C6c                óh   — t        |«      j                  d«      }t        |d|› dt        › d�|¬«      S )Nz. zNimble Search: z. See z for details.)rn   r2   rK   )Ú_unwrap_error_detailrS   r   r   )rJ   rm   rn   rK   r1   s        r(   ru   z"NimbleSearchConfig.get_error_classÑ   s@   € ô -¨]Ó;×BÑBÀ4ÓHˆÜØ#Ø% f X¨VÔ4DÐ3EÀ]ÐSØô
ð 	
r'   )Úreturnrf   )NN)
rK   údict[str, str]rL   r   rM   r   rN   r   r€   r�   ©N)
rM   r   rU   údict[str, object]rV   z2dict[str, object] | list[dict[str, object]] | NonerN   r   r€   rf   )r\   zstr | list[str]rU   rƒ   rN   r   r€   rƒ   )rx   zhttpx.Responsery   ÚLiteLLMLoggingObjrN   r   r€   r   )rm   rf   rn   ÚintrK   r�   r€   Ú	Exception)r    r!   r"   r@   Ústaticmethodr=   rP   rX   rk   r}   ru   r&   r'   r(   r:   r:   R   s  „ Ø4€Oàòó ðð #Ø#ð	
àð
ð ð
ð ð	
ð
 ð
ð 
ó
ðD DHð	
)àð
)ð +ð
)ð Að	
)ð
 ð
)ð 
ó
)ð"
àð"
ð +ð"
ð ð	"
ð
 
ó"
ðH(
à$ð(
ð 'ð(
ð ð	(
ð
 
ó(
ðT
àð
ð ð
ð  ð	
ð
 
ô
r'   r:   c                óŒ   — 	 t         j                  | «      }|j                  xs |j                  xs | S # t        $ r | cY S w xY w)z«
    Surface the human-readable message inside Nimble's error envelopes.

    Falls back to the raw body for anything else (CDN HTML pages, plain text, other shapes).
    )r0   rt   r   r1   r2   )rm   Úbodys     r(   r   r   ß   sH   € ðÜ$×8Ñ8¸ÓGˆð �;‰;Ò7˜$Ÿ,™,Ò7¨-Ð7øô ò ØÒðús   ‚5 µAÁAc                óò   — 	 t         j                  | «      }t	        dt        d„ |D «       «      fdt        d„ |D «       «      ffD ��ci c]
  \  }}|r||“Œ c}}«      S # t        $ r	 t        cY S w xY wc c}}w )a=  
    Split the unified `search_domain_filter` into Nimble's include/exclude lists.

    Follows the Perplexity unified spec, where a `-` prefix means "exclude this domain".
    Anything that is not a list of strings is ignored rather than raising, since it only
    ever narrows a search that is otherwise valid.
    Úinclude_domainsc              3  óJ   K  — | ]  }|sŒ|j                  d «      rŒ|–— Œ y­w)ú-N)Ú
startswith©Ú.0Úds     r(   ú	<genexpr>z"_domain_filters.<locals>.<genexpr>ü   s   è ø€ Ò)\°ÂÈ!Ï,É,ÐWZÕJ[¬!Ñ)\ùs   ‚#Š#œ#Úexclude_domainsc              3  óh   K  — | ]*  }|j                  d «      sŒt        |«      dkD  sŒ$|dd –— Œ, y­w)r�   é   N)rŽ   Úlenr�   s     r(   r’   z"_domain_filters.<locals>.<genexpr>ý   s1   è ø€ Ò)e°AÀAÇLÁLÐQTÕDUÔZ]Ð^_ÓZ`ÐcdÓZd¨!¨A¨B¬%Ñ)eùs   ‚2™2¨
2)r3   Úvalidate_pythonr   r4   r   Útuple)r[   Údomainsr6   r7   s       r(   rb   rb   ì   sŽ   € ðÜ+×;Ñ;Ð<PÓQˆô ð #¤EÑ)\°WÔ)\Ó$\Ð]Ø"¤EÑ)e¸Ô)eÓ$eÐfð÷	
á��Uñ ð �‰Jó	
ó	ð 	øô ò ÜŠðüó	
s   ‚A ÁA3
ÁA0Á/A0c                ó`   — 	 t         j                  | «      j                  S # t        $ r Y y w xY wr‚   )r-   Úmodel_validater.   r   )r   s    r(   rw   rw     s0   € ðÜ×-Ñ-¨oÓ>×KÑKÐKøÜò Ùðús   ‚! ¡	-¬-)r6   rf   r7   r   r€   úMapping[str, object])rm   rf   r€   rf   )r[   r   r€   rœ   )r   r   r€   r   )*r#   Ú
__future__r   Úcollections.abcr   Útypesr   Útypingr   r   ÚhttpxÚpydanticr   r	   r
   r   Ú)litellm.llms.base_llm.chat.transformationr   Ú+litellm.llms.base_llm.search.transformationr   r   r   Úlitellm.secret_managers.mainr   Ú*litellm.litellm_core_utils.litellm_loggingr   r„   r   r%   r   r*   r-   r0   r˜   rf   r3   r4   r8   r:   r   rb   rw   r&   r'   r(   ú<module>r§      sÃ   ðòõ #å #Ý "ß 'ã ß HÓ Hå F÷ñ õ
 8áÝWàRÐ �%Ó Rô#�Iô #ô'˜Iô 'ô$�iô $ô�Yô ñ (¨¨c°3¨h©Ó8Ð �EÓ 8á(8¸Ó(<€Ð
%Ó <óMô
J
Ð)ô J
óZ
8óô0r'   