View Source Anthropix (Anthropix v0.5.0)

Anthropix

License

Anthropix is an open-source Elixir client for the Anthropic API, providing a simple and convenient way to integrate Claude, Anthropic's powerful language model, into your applications.

  • ✅ API client fully implementing the Anthropic API
  • 🧰 Tool use (function calling)
  • ⚡ Prompt caching
  • 📦 Message batching (Anthropix.Batch)
  • 🛜 Streaming API requests
    • Stream to an Enumerable
    • Or stream messages to any Elixir process

Installation

The package can be installed by adding anthropix to your list of dependencies in mix.exs.

def deps do
  [
    {:anthropix, "~> 0.5.0"}
  ]
end

Quickstart

Beta features

Anthropic frequently ship new features under a beta flag, requiring headers to be added to your requests to take advantage of the feature. This library currently enables the following beta headers by default:

  • prompt-caching-2024-07-31
  • message-batches-2024-09-24

If required, beta headers can be customised with init/2.

Initiate a client.

See Anthropix.init/2.

iex> client = Anthropix.init(api_key)

Chat with Claude

See Anthropix.chat/2.

iex> messages = [
...>   %{role: "user", content: "Why is the sky blue?"},
...>   %{role: "assistant", content: "Due to rayleigh scattering."},
...>   %{role: "user", content: "How is that different than mie scattering?"},
...> ]

iex> Anthropix.chat(client, [
...>   model: "claude-3-opus-20240229",
...>   messages: messages,
...> ])
{:ok, %{"content" => [%{
  "type" => "text",
  "text" => "Mie scattering affects all wavelengths similarly, while Rayleigh favors shorter ones."
}], ...}}

Streaming

A streaming request can be initiated by setting the :stream option.

When :stream is true a lazy Enumerable.t/0 is returned which can be used with any Stream functions.

iex> {:ok, stream} = Anthropix.chat(client, [
...>   model: "claude-3-opus-20240229",
...>   messages: messages,
...>   stream: true,
...> ])
{:ok, #Function<52.53678557/2 in Stream.resource/3>}

iex> stream
...> |> Stream.each(&update_ui_with_chunk/1)
...> |> Stream.run()
:ok

Because the above approach builds the Enumerable.t/0 by calling receive, using this approach inside GenServer callbacks may cause the GenServer to misbehave. Setting the :stream option to a pid/0 returns a Task.t/0 which will send messages to the specified process.

Summary

Types

Client struct

Message content block.

JSON schema for the tool input shape.

Chat message

Client response

Tool.

Functions

Chat with Claude. Send a list of structured input messages with text and/or image content, and Claude will generate the next message in the conversation.

Calling init/1 without passing an API key, creates a new Anthropix API client using the API key set in your application's config.

Calling init/2 with an API key creates a new Anthropix API client, using the given API key. Optionally, a keyword list of options can be passed through to Req.new/1.

Types

client()

@type client() :: %Anthropix{req: Req.Request.t()}

Client struct

content_block()

@type content_block() ::
  content_text() | content_media() | content_tool_use() | content_tool_result()

Message content block.

content_media()

@type content_media() :: %{
  type: String.t(),
  source: %{type: String.t(), media_type: String.t(), data: String.t()}
}

content_text()

@type content_text() :: %{type: String.t(), text: String.t()}

content_tool_result()

@type content_tool_result() :: %{
  type: String.t(),
  tool_use_id: String.t(),
  content: %{optional(String.t()) => String.t()}
}

content_tool_use()

@type content_tool_use() :: %{
  type: String.t(),
  id: String.t(),
  name: String.t(),
  input: %{optional(String.t()) => String.t()}
}

input_schema()

@type input_schema() :: %{
  :type => String.t(),
  :properties => %{
    optional(String.t()) => %{
      optional(:enum) => [String.t()],
      type: String.t(),
      description: String.t()
    }
  },
  optional(:required) => [String.t()]
}

JSON schema for the tool input shape.

message()

@type message() :: %{role: String.t(), content: String.t() | [content_block()]}

Chat message

A chat message is a map/0 with the following fields:

  • :role (String.t/0) - Required. The role of the message, either user or assistant.
  • :content - Required. Message content, either a single string or an array of content blocks.

response()

@type response() :: {:ok, map() | Enumerable.t() | Task.t()} | {:error, term()}

Client response

tool()

@type tool() :: %{
  name: String.t(),
  description: String.t(),
  input_schema: input_schema()
}

Tool.

A chat tool is a map/0 with the following fields:

  • :name (String.t/0) - Required. Name of the tool.
  • :description (String.t/0) - Required. Description of the tool
  • :input_schema - Required. JSON schema for the tool input shape that the model will produce in tool_use output content blocks.
  • :cache_control - Cache-control parameter.

Functions

chat(client, params \\ [])

@spec chat(
  client(),
  keyword()
) :: response()

Chat with Claude. Send a list of structured input messages with text and/or image content, and Claude will generate the next message in the conversation.

Options

  • :model (String.t/0) - Required. The model that will complete your prompt.
  • :messages (list of map/0) - Required. Input messages.
  • :system - System prompt.
  • :max_tokens (integer/0) - The maximum number of tokens to generate before stopping. The default value is 4096.
  • :metadata - A map describing metadata about the request.
  • :stop_sequences (list of String.t/0) - Custom text sequences that will cause the model to stop generating.
  • :stream - Whether to incrementally stream the response using server-sent events. The default value is false.
  • :temperature (float/0) - Amount of randomness injected into the response.
  • :tools (list of map/0) - A list of tools the model may call.
  • :tool_choice (map/0) - How to use the provided tools.
    • :type (String.t/0) - Required. One of auto, any or tool.
    • :name (String.t/0) - The name of the tool to use.
  • :top_k (integer/0) - Only sample from the top K options for each subsequent token.
  • :top_p (float/0) - Amount of randomness injected into the response.

Message structure

Each message is a map with the following fields:

  • :role (String.t/0) - Required. The role of the message, either user or assistant.
  • :content - Required. Message content, either a single string or an array of content blocks.

Tool structure

Each tool is a map with the following fields:

  • :name (String.t/0) - Required. Name of the tool.
  • :description (String.t/0) - Required. Description of the tool
  • :input_schema - Required. JSON schema for the tool input shape that the model will produce in tool_use output content blocks.
  • :cache_control - Cache-control parameter.

Examples

iex> messages = [
...>   %{role: "user", content: "Why is the sky blue?"},
...>   %{role: "assistant", content: "Due to rayleigh scattering."},
...>   %{role: "user", content: "How is that different than mie scattering?"},
...> ]

iex> Anthropix.chat(client, [
...>   model: "claude-3-opus-20240229",
...>   messages: messages,
...> ])
{:ok, %{"content" => [%{
  "type" => "text",
  "text" => "Mie scattering affects all wavelengths similarly, while Rayleigh favors shorter ones."
}], ...}}

# Passing true to the :stream option initiates an async streaming request.
iex> Anthropix.chat(client, [
...>   model: "claude-3-opus-20240229",
...>   messages: messages,
...>   stream: true,
...> ])
{:ok, #Function<52.53678557/2 in Stream.resource/3>}

init()

@spec init() :: client()

Calling init/1 without passing an API key, creates a new Anthropix API client using the API key set in your application's config.

config :anthropix, :api_key, "sk-ant-your-key"

If given, a keyword list of options will be passed to Req.new/1.

Examples

iex> client = Anthropix.init()
%Anthropix{}

init(opts)

@spec init(keyword()) :: client()

init(api_key, opts \\ [])

@spec init(
  String.t(),
  keyword()
) :: client()

Calling init/2 with an API key creates a new Anthropix API client, using the given API key. Optionally, a keyword list of options can be passed through to Req.new/1.

Examples

iex> client = Anthropix.init("sk-ant-your-key", receive_timeout: :infinity)
%Anthropix{}