4.2 KiB
Claude API — Ruby
Note: The Ruby SDK supports the Claude API. A tool runner is available in beta via
client.beta.messages.tool_runner(). Agent SDK is not yet available for Ruby.
Installation
gem install anthropic
Client Initialization
require "anthropic"
# Default (uses ANTHROPIC_API_KEY env var)
client = Anthropic::Client.new
# Explicit API key
client = Anthropic::Client.new(api_key: "your-api-key")
Basic Message Request
message = client.messages.create(
model: :"{{OPUS_ID}}",
max_tokens: 16000,
messages: [
{ role: "user", content: "What is the capital of France?" }
]
)
# content is an array of polymorphic block objects (TextBlock, ThinkingBlock,
# ToolUseBlock, ...). .type is a Symbol — compare with :text, not "text".
# .text raises NoMethodError on non-TextBlock entries.
message.content.each do |block|
puts block.text if block.type == :text
end
Extended Thinking
Fable 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6: Use adaptive thinking.
budget_tokensis removed on Fable 5, Opus 4.8, and 4.7 (400 if sent); deprecated on Opus 4.6 and Sonnet 4.6. Older models: Usethinking: { type: "enabled", budget_tokens: N }(must be <max_tokens, min 1024).
message = client.messages.create(
model: :"{{OPUS_ID}}",
max_tokens: 16000,
thinking: { type: "adaptive" },
messages: [{ role: "user", content: "Solve: 27 * 453" }]
)
message.content.each do |block|
case block.type
when :thinking then puts "Thinking: #{block.thinking}"
when :text then puts "Response: #{block.text}"
end
end
Prompt Caching
system_: (trailing underscore — avoids shadowing Kernel#system) takes an array of text blocks; set cache_control on the last block. Plain hashes work via the OrHash type alias. For placement patterns and the silent-invalidator audit checklist, see shared/prompt-caching.md.
message = client.messages.create(
model: :"{{OPUS_ID}}",
max_tokens: 16000,
system_: [
{ type: "text", text: long_system_prompt, cache_control: { type: "ephemeral" } }
],
messages: [{ role: "user", content: "Summarize the key points" }]
)
For 1-hour TTL: cache_control: { type: "ephemeral", ttl: "1h" }. There's also a top-level cache_control: on messages.create that auto-places on the last cacheable block.
Verify hits via message.usage.cache_creation_input_tokens / message.usage.cache_read_input_tokens.
Stop Details
When stop_reason is :refusal, the response includes structured stop_details:
if message.stop_reason == :refusal && message.stop_details
puts "Category: #{message.stop_details.category}" # e.g. :cyber, :bio, :reasoning_extraction, :frontier_llm, or nil — see docs for the full set
puts "Explanation: #{message.stop_details.explanation}"
end
Refusal fallbacks ({{FABLE_NAME}}) — opt in by default. Fallbacks are opt-in: without them a refused request simply stops. New {{FABLE_ID}} code should include the server-side fallbacks parameter (beta header server-side-fallback-2026-06-01, fallbacks: [{model: "{{OPUS_ID}}"}] on the beta messages call) by default. The exact Ruby binding (and the client-side middleware for providers without server-side support) is not documented here — WebFetch the Ruby SDK repo's examples/ from shared/live-sources.md; full semantics in shared/model-migration.md → Migrating to {{FABLE_NAME}} → refusal stop reason.
Beta Features
betas: is only valid on client.beta.messages.create, not the non-beta path.
Task budgets
response = client.beta.messages.create(
model: :"{{OPUS_ID}}",
max_tokens: 16000,
output_config: { task_budget: { type: :tokens, total: 64_000 } },
tools: [...],
messages: [...],
betas: ["task-budgets-2026-03-13"]
)
Error Type
APIStatusError exposes a .type field for programmatic error classification:
begin
client.messages.create(...)
rescue Anthropic::Errors::APIStatusError => e
puts e.type # :rate_limit_error, :overloaded_error, etc.
end