A thin client for the Anthropic API, built on Req.

Request bodies are plain maps, sent unchanged. Jibu has no model list and no parameter schema. New API fields therefore work without a new release.

client = Jibu.new(api_key: System.fetch_env!("ANTHROPIC_API_KEY"))

{:ok, response} =
  Jibu.messages(client, %{
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [%{role: "user", content: "Hello"}]
  })

Jibu.Response.text(response)

Start with the Getting started guide.

Summary

Functions

Sends prompt as a user message and returns the text of the answer.

Counts the input tokens of a Messages API request body. The body is sent unchanged. The API does not bill this call.

Sends prompt with schema as structured output and returns the decoded JSON.

Sends a Messages API request. The body is sent unchanged.

Builds a client as a Req.Request.

Sends a Messages API request as a stream and calls fun with each event.

Functions

ask(client, prompt, opts \\ [])

@spec ask(Req.Request.t(), String.t() | [map()], keyword()) ::
  {:ok, String.t()} | {:error, Jibu.Error.t()}

Sends prompt as a user message and returns the text of the answer.

prompt is a string or a list of content blocks, see Jibu.Content.

Shortcuts

  • :system - the system prompt.
  • :cache - true marks the system prompt for prompt caching.
  • :effort - sets output_config.effort, for example :low.
  • :messages - an earlier conversation; prompt is appended to it.
  • :on_text - a function that receives each piece of text as it streams in. The answer then goes through stream/3.

Every other keyword becomes a body field unchanged, for example temperature: 0.

A refusal and output cut off at max_tokens or at the context window are errors. Use messages/2 when you need the whole response.

count_tokens(client, body)

@spec count_tokens(Req.Request.t(), map()) :: {:ok, map()} | {:error, Jibu.Error.t()}

Counts the input tokens of a Messages API request body. The body is sent unchanged. The API does not bill this call.

extract(client, prompt, schema, opts \\ [])

@spec extract(Req.Request.t(), String.t() | [map()], map(), keyword()) ::
  {:ok, term()} | {:error, Jibu.Error.t()}

Sends prompt with schema as structured output and returns the decoded JSON.

Takes the shortcuts of ask/3 except :on_text. See the structured output guide.

messages(client, body)

@spec messages(Req.Request.t(), map()) ::
  {:ok, Jibu.Response.t()} | {:error, Jibu.Error.t()}

Sends a Messages API request. The body is sent unchanged.

new(opts \\ [])

@spec new(keyword()) :: Req.Request.t()

Builds a client as a Req.Request.

Options

  • :api_key - defaults to the ANTHROPIC_API_KEY environment variable.
  • :betas - beta names sent in the anthropic-beta header.
  • :base_url - defaults to https://api.anthropic.com.
  • :model, :max_tokens - defaults for messages/2 bodies. count_tokens/2 takes only the model.
  • :defaults - a map of further body defaults, for example %{temperature: 0}.

A field set in a request body always wins over its default.

Every other option goes to Req.merge/2, for example :receive_timeout, :headers or plug: {Req.Test, MyStub}. Headers merge by name with the API headers.

Jibu retries transient failures. Pass retry: false to turn that off. The errors guide lists the rules.

stream(client, body, fun)

@spec stream(Req.Request.t(), map(), (map() -> any())) ::
  {:ok, Jibu.Response.t()} | {:error, Jibu.Error.t()}

Sends a Messages API request as a stream and calls fun with each event.

Jibu sets stream: true and sends the body otherwise unchanged. fun receives every server-sent event as a decoded map, including ping and unknown types. The result is the assembled message as a Jibu.Response.

An error event returns {:error, %Jibu.Error{}} with the partial message in body. Jibu does not retry once events have arrived when :retry is a function. See the streaming guide.