Anthropic Provider

The Anthropic provider connects to Claude models via the Anthropic API.

Installation

Add the Anthropic gem to your Gemfile:

gem 'anthropic'

Configuration

Configure your Anthropic API key:

Riffer.configure do |config|
  config.anthropic.api_key = ENV['ANTHROPIC_API_KEY']
end

Or per-agent:

class MyAgent < Riffer::Agent
  model 'anthropic/claude-4-5-haiku-20251001'
  provider_options api_key: ENV['ANTHROPIC_API_KEY']
end

Supported Models

Use Anthropic model IDs in the anthropic/model format:

model 'anthropic/claude-haiku-4-5-20251001'
model 'anthropic/claude-sonnet-4-5-20250929'
model 'anthropic/claude-opus-4-5-20251101'

Model Options

temperature

Controls randomness:

model_options temperature: 0.7

max_tokens

Maximum tokens in response:

model_options max_tokens: 4096

top_p

Nucleus sampling parameter:

model_options top_p: 0.95

top_k

Top-k sampling parameter:

model_options top_k: 250

thinking

Enable extended thinking (reasoning) for supported models. Pass the thinking configuration hash directly as Anthropic expects:

# Enable with budget tokens
model_options thinking: {type: "enabled", budget_tokens: 10000}

web_search

Enable server-side web search using Anthropic’s web_search_20250305 tool. Pass true to use defaults or a hash to merge with the tool definition:

# Enable with defaults
model_options web_search: true

# With custom configuration
model_options web_search: {max_uses: 3}

Example

Riffer.configure do |config|
  config.anthropic.api_key = ENV['ANTHROPIC_API_KEY']
end

class AssistantAgent < Riffer::Agent
  model 'anthropic/claude-4-5-haiku-20251001'
  instructions 'You are a helpful assistant.'
  model_options temperature: 0.7, max_tokens: 4096
end

agent = AssistantAgent.new
puts agent.generate("Explain quantum computing")

Streaming

agent.stream("Tell me about Claude models").each do |event|
  case event
  when Riffer::StreamEvents::TextDelta
    print event.content
  when Riffer::StreamEvents::TextDone
    puts "\n[Complete]"
  when Riffer::StreamEvents::ReasoningDelta
    print "[Thinking] #{event.content}"
  when Riffer::StreamEvents::ReasoningDone
    puts "\n[Thinking Complete]"
  when Riffer::StreamEvents::ToolCallDone
    puts "[Tool: #{event.name}]"
  end
end

Tool Calling

Anthropic provider converts tools to the Anthropic tool format:

class WeatherTool < Riffer::Tool
  description "Gets the current weather for a location"

  params do
    required :city, String, description: "The city name"
    optional :unit, String, description: "Temperature unit (celsius or fahrenheit)"
  end

  def call(context:, city:, unit: "celsius")
    # Implementation
    "It's 22 degrees #{unit} in #{city}"
  end
end

class WeatherAgent < Riffer::Agent
  model 'anthropic/claude-4-5-haiku-20251001'
  uses_tools [WeatherTool]
end

Extended Thinking

Extended thinking enables Claude to reason through complex problems before responding. This is available on Claude 3.7 models.

class ReasoningAgent < Riffer::Agent
  model 'anthropic/claude-4-5-haiku-20251001'
  model_options thinking: {type: "enabled", budget_tokens: 10000}
end

When streaming with extended thinking enabled, you’ll receive ReasoningDelta events containing the model’s thought process, followed by a ReasoningDone event when thinking completes:

agent.stream("Solve this complex math problem").each do |event|
  case event
  when Riffer::StreamEvents::ReasoningDelta
    # Model's internal reasoning
    print "[Thinking] #{event.content}"
  when Riffer::StreamEvents::ReasoningDone
    puts "\n[Thinking complete]"
  when Riffer::StreamEvents::TextDelta
    # Final response
    print event.content
  end
end

Web search allows Claude to search the web for up-to-date information. When enabled, the provider injects the web_search_20250305 server tool into the request.

class SearchAgent < Riffer::Agent
  model 'anthropic/claude-4-5-haiku-20251001'
  model_options web_search: true
end

agent = SearchAgent.new
agent.stream("What happened in tech news today?").each do |event|
  case event
  when Riffer::StreamEvents::WebSearchStatus
    puts "[search: #{event.status}]"
    puts "  query: #{event.query}" if event.query
  when Riffer::StreamEvents::WebSearchDone
    puts "[search complete: #{event.query}]"
    event.sources.each { |s| puts "  - #{s[:title]}: #{s[:url]}" }
  when Riffer::StreamEvents::TextDelta
    print event.content
  end
end

Anthropic emits sources with title and url on the WebSearchDone event.

Message Format

The provider converts Riffer messages to Anthropic format:

Riffer Message Anthropic Format
System Added to system array as {type: "text", text: ...}
User {role: "user", content: "..."}
Assistant {role: "assistant", content: [...]} with text/tool_use blocks
Tool {role: "user", content: [{type: "tool_result", ...}]}

Direct Provider Usage

provider = Riffer::Providers::Anthropic.new(
  api_key: ENV['ANTHROPIC_API_KEY']
)

response = provider.generate_text(
  prompt: "Hello!",
  model: "claude-4-5-haiku-20251001",
  temperature: 0.7
)

puts response.content

With extended thinking:

response = provider.generate_text(
  prompt: "Explain step by step how to solve a Rubik's cube",
  model: "claude-4-5-haiku-20251001",
  thinking: { type: "enabled", budget_tokens: 10000 }
)

puts response.content