
    Rmj                         d 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 erddlmZ e G d de                      Ze G d d	e                      Zg d
ZdS )aT  Protocol definitions for request and response codecs used by ``nemo_relay.llm``.

``LlmCodec`` is used for request-side translation. It lets intercepts work
against ``AnnotatedLLMRequest`` instead of provider-specific raw payloads.

``LlmResponseCodec`` is used for response-side translation. It lets NeMo Relay attach
an ``AnnotatedLLMResponse`` to emitted ``LLMEnd`` events without changing the
return value of ``llm.execute()`` or ``llm.stream_execute()``.

Example::

    from nemo_relay import AnnotatedLLMRequest, LLMRequest, llm
    from nemo_relay.codecs import LlmCodec, OpenAIChatCodec

    class DemoCodec(LlmCodec):
        def decode(self, request: LLMRequest) -> AnnotatedLLMRequest:
            return AnnotatedLLMRequest(
                request.content.get("messages", []),
                model=request.content.get("model"),
            )

        def encode(self, annotated: AnnotatedLLMRequest, original: LLMRequest) -> LLMRequest:
            content = {**original.content, "messages": annotated.messages}
            if annotated.model is not None:
                content["model"] = annotated.model
            return LLMRequest(original.headers, content)

    async def impl(request: LLMRequest):
        return {"id": "r1", "choices": [{"message": {"role": "assistant", "content": "hi"}}]}

    # Request-side codec for intercepts, response-side codec for event annotation.
    result = await llm.execute(
        "demo-model",
        LLMRequest({}, {"messages": [{"role": "user", "content": "hello"}]}),
        impl,
        codec=DemoCodec(),
        response_codec=OpenAIChatCodec(),
    )
    )TYPE_CHECKINGProtocolruntime_checkable)Json)AnnotatedLLMRequestAnthropicMessagesCodec
LLMRequestOpenAIChatCodecOpenAIResponsesCodec)AnnotatedLLMResponsec                   6    e Zd ZdZdedefdZdededefdZdS )	LlmCodeca  Protocol for request codecs used by annotated LLM intercepts.

    ``decode()`` converts a provider-specific ``LLMRequest`` into an
    ``AnnotatedLLMRequest`` so request intercepts can work with a normalized
    structure. ``encode()`` merges any annotated edits back into the original
    raw payload before the provider callback is invoked.

    Notes:
        ``encode()`` should preserve unknown provider-specific fields whenever
        possible instead of rebuilding the payload from scratch. That keeps
        transport-specific settings intact even when an intercept edits the
        normalized representation.

    Example::

        from nemo_relay import AnnotatedLLMRequest, LLMRequest
        from nemo_relay.codecs import LlmCodec

        class DemoCodec(LlmCodec):
            def decode(self, request: LLMRequest) -> AnnotatedLLMRequest:
                return AnnotatedLLMRequest(
                    request.content.get("messages", []),
                    model=request.content.get("model"),
                )

            def encode(
                self,
                annotated: AnnotatedLLMRequest,
                original: LLMRequest,
            ) -> LLMRequest:
                content = {**original.content, "messages": annotated.messages}
                if annotated.model is not None:
                    content["model"] = annotated.model
                return LLMRequest(original.headers, content)
    requestreturnc                     dS )ag  Decode a raw provider request into ``AnnotatedLLMRequest``.

        Args:
            request: The provider-specific request payload received by
                ``nemo_relay.llm.execute()`` or ``nemo_relay.llm.stream_execute()``.

        Returns:
            AnnotatedLLMRequest: The normalized request consumed by annotated
            intercepts.
        N )selfr   s     Y/home/thesage/.hermes/hermes-agent/venv/lib/python3.11/site-packages/nemo_relay/codecs.pydecodezLlmCodec.decodea   	     	    	annotatedoriginalc                     dS )a  Merge annotated edits back into the original raw request.

        Args:
            annotated: The normalized request after intercepts have applied any
                edits.
            original: The original provider-specific request passed into the
                runtime before normalization.

        Returns:
            LLMRequest: The provider-specific request that should be forwarded
            to the provider callback.
        Nr   )r   r   r   s      r   encodezLlmCodec.encoden   s	     	r   N)__name__
__module____qualname____doc__r	   r   r   r   r   r   r   r   r   ;   sl        " "Hj -@     3 z j      r   r   c                   "    e Zd ZdZdeddfdZdS )LlmResponseCodeca\  Protocol for codecs that normalize raw LLM responses.

    A response codec is used only for observability. The value returned from
    ``llm.execute()`` or ``llm.stream_execute()`` stays unchanged; the decoded
    response is attached to the emitted ``LLMEnd`` event as
    ``annotated_response``.

    Example::

        import nemo_relay

        result = await nemo_relay.llm.execute(
            "demo-provider",
            nemo_relay.LLMRequest({}, {"messages": [{"role": "user", "content": "hi"}]}),
            impl,
            response_codec=nemo_relay.codecs.OpenAIChatCodec(),
        )
    responser   r   c                     dS )aQ  Decode a raw provider response into ``AnnotatedLLMResponse``.

        Args:
            response: The raw JSON-compatible value returned by the provider
                callback.

        Returns:
            AnnotatedLLMResponse: The normalized response attached to the
            ``LLMEnd`` event for downstream subscribers.
        Nr   )r   r"   s     r   decode_responsez LlmResponseCodec.decode_response   r   r   N)r   r   r   r   r   r$   r   r   r   r!   r!   ~   sA         & 1G      r   r!   )r   r   r   r!   r
   r   N)r   typingr   r   r   
nemo_relayr   nemo_relay._nativer   r   r	   r
   r   r   r   r!   __all__r   r   r   <module>r)      s)  & &P > = = = = = = = = =                     8777777 ? ? ? ? ?x ? ? ?D     x   D  r   