ask-llm-providers
All LLM providers for the ask-rb ecosystem in one gem. Implements Ask::Provider
from ask-core with a capabilities-based interface.
Supported Providers
| Provider | Auth | Implementation |
|---|---|---|
| OpenAI + all OpenAI-compatible | Ask::Auth.resolve(:openai_api_key) |
Ask::Providers::OpenAI |
| Anthropic (Claude) | Ask::Auth.resolve(:anthropic_api_key) |
Ask::Providers::Anthropic |
| Google Gemini | Ask::Auth.resolve(:gemini_api_key) |
Ask::Providers::Google |
| Vertex AI | GCP service account | Ask::Providers::Google (via Vertex) |
| Amazon Bedrock | AWS credentials chain | Ask::Providers::Bedrock |
| Ollama (local) | None needed | Ask::Providers::Ollama |
| Mistral AI | Ask::Auth.resolve(:mistral_api_key) |
Ask::Providers::Mistral |
| Cloudflare Workers AI | Ask::Auth.resolve(:cloudflare_api_key) |
Ask::Providers::Cloudflare |
Installation
gem "ask-llm-providers"
Usage
require "ask-llm-providers"
# All providers are auto-registered with Ask::Models
models = Ask::Models.find("gpt-4o")
# => { provider: :openai, capabilities: [...] }
# Use a provider directly
provider = Ask::Providers::OpenAI.new
provider.chat(conversation, tools: [], model: "gpt-4o") do |chunk|
print chunk.content
end
Capabilities
Each provider and model exposes its capabilities:
provider = Ask::Providers::OpenAI.new
provider.capabilities
# => { chat: true, streaming: true, tool_calls: true, vision: true, thinking: true,
# :structured_output, :embed, :transcribe, :paint, :moderate]
model = Ask::Models.find("claude-sonnet-4-5")
model[:capabilities]
# => { chat: true, streaming: true, tool_calls: true, vision: true, thinking: true, :prompt_caching]
# Unsupported capabilities raise a helpful error
provider = Ask::Providers::Anthropic.new
provider.(["text"], model: "claude-sonnet-4-5")
# => Ask::CapabilityNotSupported: Anthropic (claude-sonnet-4-5) does not support embeddings.
Streaming
stream = provider.chat(
[{ role: "user", content: "Tell me a story" }],
model: "gpt-4o",
stream: true
) do |chunk|
print chunk.content
end
# After streaming completes, you can access the full response
puts stream.accumulated_text
puts stream.accumulated_usage
Tool Calls
tools = [{
name: "get_weather",
description: "Get weather for a location",
parameters: {
type: "object",
properties: { location: { type: "string" } },
required: ["location"]
}
}]
response = provider.chat(
[{ role: "user", content: "What's the weather in NYC?" }],
model: "gpt-4o",
tools: tools
)
# response.tool_call? => true
# response.tool_calls => [{ id: "call_1", name: "get_weather", arguments: '{"location":"NYC"}' }]
Error Handling
Provider errors map to structured Ask::Error types:
Ask::RateLimitError # 429 — retry with backoff
Ask::Unauthorized # 401/403 — check your API key
Ask::ServerError # 500 — provider issue
Ask::ServiceUnavailable # 503 — temporary
Ask::ContextLengthExceeded # context window exceeded
Ask::ProviderError # other provider errors
Ask::CapabilityNotSupported # feature not available on this model
Development
bin/setup
bundle exec rake test
License
MIT