langchain icon indicating copy to clipboard operation
langchain copied to clipboard

Add tool_choice for OpenAI and Anthropic

Open avergin opened this issue 8 months ago • 2 comments

This PR adds tool_choice option to both OpenAI and Anthropic models.

For both models, I've created a tool_choice attribute inside the model structs that embeds a ToolChoice struct with attributes that are specific to each model.

For ChatOpenAI:

  defmodule ToolChoice do
    use Ecto.Schema

    defmodule Function do
      use Ecto.Schema
      @primary_key false
      embedded_schema do
        field :name, :string
      end

      @doc """
      Setup a ChatOpenAI Function with name
      """
      @spec changeset(%Function{}, map()) :: Ecto.Changeset.t()
      def changeset(%Function{}=function, %{}=attrs) do
        function
        |> cast(attrs, [:name])
        |> validate_required([:name])
      end

    end

    @primary_key false
    embedded_schema do
      field :type, Ecto.Enum, values: [:function, :required, :none, :auto]
      embeds_one :function, Function
    end

    @doc """
    Setup a ChatOpenAI ToolChoice configuration
    """
    @spec changeset(%ToolChoice{}, map()) :: Ecto.Changeset.t()
    def changeset(%ToolChoice{}=tool_choice, %{}=attrs) do
      tool_choice
      |> cast(attrs, [:type])
      |> validate_required([:type])
      |> validate_type()
    end

    defp validate_type(changeset) do
      case get_change(changeset, :type) do
        :function -> cast_embed(changeset, :function, required: true, with: &Function.changeset/2)
        _ -> changeset
      end
    end
  end

For ChatAnthropic:

  defmodule ToolChoice do
    use Ecto.Schema

    @primary_key false
    embedded_schema do
      field :type, Ecto.Enum, values: [:tool, :auto, :any]
      field :name, :string
    end

    @doc """
    Setup a ChatAnthropic ToolChoice configuration
    """
    @spec changeset(%ToolChoice{}, map()) :: Ecto.Changeset.t()
    def changeset(%ToolChoice{}=tool_choice, %{}=attrs) do
      tool_choice
      |> cast(attrs, [:type, :name])
      |> validate_required([:type])
      |> validate_type()
    end

    defp validate_type(changeset) do
      case get_change(changeset, :type) do
        :tool -> validate_required(changeset, [:name])
        _ -> changeset
      end
    end
  end

avergin avatar Jun 21 '24 11:06 avergin