Claudio.Messages (Claudio v0.7.0)
View SourceClient for the Anthropic Messages API.
This module provides functions for creating messages, counting tokens, and working with streaming responses. It supports both a structured Request/Response API and a legacy map-based API for backward compatibility.
New API (Recommended)
The new API provides type-safe request building and structured response handling:
alias Claudio.Messages.{Request, Response}
# Build a request
request = Request.new("claude-opus-5-5")
|> Request.add_message(:user, "Hello!")
|> Request.set_max_tokens(1024)
# Create message
{:ok, response} = Claudio.Messages.create(client, request)
# Extract text
text = Response.get_text(response)Features
- Streaming: Real-time response streaming with SSE parsing
- Tool calling: Function calling with structured schemas
- Prompt caching: Cache large contexts to reduce costs
- Vision: Send images for analysis
- Token counting: Estimate costs before making requests
- Type safety: Structured Request/Response types
Streaming
For streaming responses, enable streaming and consume the stream in one pass:
request = Request.new("claude-opus-5-5")
|> Request.add_message(:user, "Tell me a story")
|> Request.set_max_tokens(1024)
|> Request.enable_streaming()
{:ok, stream_response} = Claudio.Messages.create(client, request)
{:ok, response} =
Claudio.Messages.Stream.to_response(stream_response, on_text: &IO.write/1)
IO.inspect(response.usage)Tool Calling
Define and use tools for function calling:
alias Claudio.Tools
tool = Tools.define_tool("get_weather", "Get weather", %{
type: "object",
properties: %{location: %{type: "string"}},
required: ["location"]
})
request = Request.new("claude-opus-5-5")
|> Request.add_message(:user, "What's the weather?")
|> Request.add_tool(tool)
|> Request.set_max_tokens(1024)
{:ok, response} = Claudio.Messages.create(client, request)
# Check for tool uses
if Tools.has_tool_uses?(response) do
tool_uses = Tools.extract_tool_uses(response)
# Execute tools and continue conversation...
endPrompt Caching
Cache large contexts to reduce costs (up to 90% savings):
request = Request.new("claude-opus-5-5")
|> Request.set_system_with_cache("Large context here...", ttl: "5m")
|> Request.add_message(:user, "Question about context")
|> Request.set_max_tokens(1024)
{:ok, response} = Claudio.Messages.create(client, request)
# Check cache metrics
IO.inspect(response.usage.cache_read_input_tokens)Legacy API (Backward Compatible)
The original API using raw maps is still supported:
{:ok, response} = Claudio.Messages.create_message(client, %{
"model" => "claude-opus-5-5",
"max_tokens" => 1024,
"messages" => [%{"role" => "user", "content" => "Hello"}]
})Error Handling
All functions return {:ok, result} or {:error, reason} tuples:
case Claudio.Messages.create(client, request) do
{:ok, response} ->
IO.puts("Success!")
{:error, %Claudio.APIError{} = error} ->
IO.puts("API Error: #{error.message}")
{:error, reason} ->
IO.puts("Error: #{inspect(reason)}")
end
Summary
Functions
Counts tokens for a message request.
Creates a message using the new structured API.
Creates a message (legacy API, backward compatible).
Functions
@spec count_tokens(Req.Request.t(), map() | Claudio.Messages.Request.t()) :: {:ok, map()} | {:error, Claudio.APIError.t() | term()}
Counts tokens for a message request.
Emits the [:claudio, :messages, :count_tokens] span (and, per attempt, [:claudio, :http, :request]).
See the telemetry guide.
Example
{:ok, count} = Claudio.Messages.count_tokens(client, %{
"model" => "claude-opus-5-5",
"messages" => [%{"role" => "user", "content" => "Hello"}]
})
IO.puts("Input tokens: #{count.input_tokens}")
@spec create(Req.Request.t(), Claudio.Messages.Request.t() | map()) :: {:ok, Claudio.Messages.Response.t() | Req.Response.t()} | {:error, Claudio.APIError.t() | term()}
Creates a message using the new structured API.
Accepts either a Request struct or a raw map (for backward compatibility).
Returns either a Response struct or raw stream data for streaming requests.
Emits the [:claudio, :messages, :create] span (and, per attempt, [:claudio, :http, :request]).
See the telemetry guide. The error key on a failed :stop is deprecated (it
can contain the API's error body or a malformed 200's body); use error_type.
Examples
# Using Request builder
request = Request.new("claude-opus-5-5")
|> Request.add_message(:user, "Hello!")
|> Request.set_max_tokens(1024)
{:ok, response} = Claudio.Messages.create(client, request)
# Using raw map (backward compatible)
{:ok, response} = Claudio.Messages.create(client, %{
"model" => "claude-opus-5-5",
"max_tokens" => 1024,
"messages" => [%{"role" => "user", "content" => "Hello"}]
})
@spec create_message(Req.Request.t(), map()) :: {:ok, map() | Req.Response.t()} | {:error, term()}
Creates a message (legacy API, backward compatible).
This function maintains backward compatibility with the original implementation.
For new code, consider using create/2 instead.
Emits the [:claudio, :messages, :create] span (and, per attempt, [:claudio, :http, :request]).
See the telemetry guide. The error key on a failed :stop is deprecated (it
can contain the API's error body or a malformed 200's body); use error_type.