jeevesagent.model
=================

.. py:module:: jeevesagent.model

.. autoapi-nested-parse::

   Model adapters.

   * :class:`EchoModel` — zero-key, echoes the prompt; default
   * :class:`ScriptedModel` — replays canned turns for tests
   * :class:`AnthropicModel` — Claude via the ``anthropic`` SDK
   * :class:`OpenAIModel` — GPT via the ``openai`` SDK

   The provider adapters import their SDK lazily inside ``__init__`` so
   ``from jeevesagent.model import AnthropicModel`` works even without
   the corresponding extra installed; the ImportError is raised only when
   the constructor needs to build a default client.



Submodules
----------

.. toctree::
   :maxdepth: 1

   /api/jeevesagent/model/anthropic/index
   /api/jeevesagent/model/echo/index
   /api/jeevesagent/model/litellm/index
   /api/jeevesagent/model/openai/index
   /api/jeevesagent/model/retrying/index
   /api/jeevesagent/model/scripted/index


Classes
-------

.. autoapisummary::

   jeevesagent.model.AnthropicModel
   jeevesagent.model.EchoModel
   jeevesagent.model.LiteLLMModel
   jeevesagent.model.OpenAIModel
   jeevesagent.model.ScriptedModel
   jeevesagent.model.ScriptedTurn


Package Contents
----------------

.. py:class:: AnthropicModel(model: str = 'claude-opus-4-7', *, client: Any = None, api_key: str | None = None, max_tokens: int = DEFAULT_MAX_TOKENS)

   Talks to Claude via :class:`anthropic.AsyncAnthropic`.


   .. py:method:: complete(messages: list[jeevesagent.core.types.Message], *, tools: list[jeevesagent.core.types.ToolDef] | None = None, temperature: float = 1.0, max_tokens: int | None = None) -> tuple[str, list[jeevesagent.core.types.ToolCall], jeevesagent.core.types.Usage, str]
      :async:


      Single-shot non-streaming completion.

      Calls ``client.messages.create(...)`` (no ``stream=True``,
      no ``stream`` context manager) — Anthropic returns the full
      ``Message`` in one HTTP response. We walk its ``content``
      blocks once to assemble ``(text, tool_calls, usage,
      stop_reason)``. Used by the non-streaming hot path
      (``agent.run()``); ``agent.stream()`` keeps using
      :meth:`stream`.

      Falls back to consuming :meth:`stream` if the underlying
      client raises (test fakes that only support streaming, or
      transports that don't honour single-shot creation).



   .. py:method:: stream(messages: list[jeevesagent.core.types.Message], *, tools: list[jeevesagent.core.types.ToolDef] | None = None, temperature: float = 1.0, max_tokens: int | None = None) -> collections.abc.AsyncIterator[jeevesagent.core.types.ModelChunk]
      :async:



   .. py:attribute:: name
      :value: 'claude-opus-4-7'



.. py:class:: EchoModel(*, prefix: str = 'Echo: ', chunk_delay_s: float = 0.0, cost_per_token: float = 0.0)

   Echo-style model for tests and demos.


   .. py:method:: complete(messages: list[jeevesagent.core.types.Message], *, tools: list[jeevesagent.core.types.ToolDef] | None = None, temperature: float = 1.0, max_tokens: int | None = None) -> tuple[str, list[jeevesagent.core.types.ToolCall], jeevesagent.core.types.Usage, str]
      :async:


      Single-shot echo. Returns the echoed user prompt as one
      string with synthetic usage. No per-token chunking — used by
      the non-streaming hot path (``agent.run()``).



   .. py:method:: stream(messages: list[jeevesagent.core.types.Message], *, tools: list[jeevesagent.core.types.ToolDef] | None = None, temperature: float = 1.0, max_tokens: int | None = None) -> collections.abc.AsyncIterator[jeevesagent.core.types.ModelChunk]
      :async:



   .. py:attribute:: name
      :type:  str
      :value: 'echo'



.. py:class:: LiteLLMModel(model: str, *, api_key: str | None = None, client: Any | None = None, **litellm_kwargs: Any)

   Bases: :py:obj:`jeevesagent.model.openai.OpenAIModel`


   Talks to any LiteLLM-supported provider.

   Inherits chunk normalisation, tool-call delta aggregation, and
   message-conversion from :class:`OpenAIModel` because LiteLLM
   produces OpenAI-shaped outputs.


.. py:class:: OpenAIModel(model: str = 'gpt-4o', *, client: Any = None, api_key: str | None = None, base_url: str | None = None)

   Talks to OpenAI via :class:`openai.AsyncOpenAI`.


   .. py:method:: complete(messages: list[jeevesagent.core.types.Message], *, tools: list[jeevesagent.core.types.ToolDef] | None = None, temperature: float = 1.0, max_tokens: int | None = None) -> tuple[str, list[jeevesagent.core.types.ToolCall], jeevesagent.core.types.Usage, str]
      :async:


      Single-shot completion (no per-chunk yields).

      Tries the OpenAI non-streaming endpoint
      (``stream=False``) first. If that fails — e.g. when a test
      fake client only supports streaming, or a transport doesn't
      honor ``stream=False`` — falls back to consuming
      :meth:`stream` internally and accumulating the result. The
      fallback still saves the per-chunk yield + Event
      construction overhead on the architecture side because
      ReAct calls ``complete`` with a single ``await``.



   .. py:method:: stream(messages: list[jeevesagent.core.types.Message], *, tools: list[jeevesagent.core.types.ToolDef] | None = None, temperature: float = 1.0, max_tokens: int | None = None) -> collections.abc.AsyncIterator[jeevesagent.core.types.ModelChunk]
      :async:



   .. py:attribute:: name
      :value: 'gpt-4o'



.. py:class:: ScriptedModel(turns: list[ScriptedTurn])

   Model that emits canned responses, one per call to :meth:`stream`.


   .. py:method:: complete(messages: list[jeevesagent.core.types.Message], *, tools: list[jeevesagent.core.types.ToolDef] | None = None, temperature: float = 1.0, max_tokens: int | None = None) -> tuple[str, list[jeevesagent.core.types.ToolCall], jeevesagent.core.types.Usage, str]
      :async:


      Single-shot replay of the next scripted turn.

      Mirrors :meth:`stream` but returns the turn's text +
      tool_calls + usage in one tuple. Used by the non-streaming
      hot path (``agent.run()``); ``agent.stream()`` keeps using
      :meth:`stream` for per-chunk replay.



   .. py:method:: stream(messages: list[jeevesagent.core.types.Message], *, tools: list[jeevesagent.core.types.ToolDef] | None = None, temperature: float = 1.0, max_tokens: int | None = None) -> collections.abc.AsyncIterator[jeevesagent.core.types.ModelChunk]
      :async:



   .. py:attribute:: name
      :type:  str
      :value: 'scripted'



   .. py:property:: remaining
      :type: int



.. py:class:: ScriptedTurn

   .. py:attribute:: text
      :type:  str
      :value: ''



   .. py:attribute:: tool_calls
      :type:  list[jeevesagent.core.types.ToolCall]
      :value: []



   .. py:attribute:: usage
      :type:  jeevesagent.core.types.Usage


