ask-llm-providers 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +67 -13
- data/lib/ask/llm/models/openai.rb +69 -0
- data/lib/ask/llm/version.rb +1 -1
- data/lib/ask/provider/anthropic.rb +1 -1
- data/lib/ask/provider/bedrock.rb +1 -1
- data/lib/ask/provider/openai.rb +3 -3
- data/lib/ask-llm-providers.rb +19 -0
- metadata +20 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e1c7c2b703b28c45fa414ddf18bb9aa7ddf896c00d97418c01b8f55966e61b52
|
|
4
|
+
data.tar.gz: d0c7a219f49a0f981f2991fa72e249c813450a9d84f2269478ac733bfdad608a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dd4dbd35bc0efe7d19a5844246c76e117601d3da4d90831eedc2e53a6345c048666b28af0d5c831dfe62557eb1434c95c51668fa010bfb676032a3159ba57195
|
|
7
|
+
data.tar.gz: 47be20c465f50f4cd586df677d5f984d14c034df110606c965085bcf2a17a05f19d45e4716eda4f41884abffb3afca622a39b6ed81961a27c4bea88754b258cf
|
data/README.md
CHANGED
|
@@ -7,14 +7,14 @@ from `ask-core` with a capabilities-based interface.
|
|
|
7
7
|
|
|
8
8
|
| Provider | Auth | Implementation |
|
|
9
9
|
|---|---|---|
|
|
10
|
-
| **OpenAI** + all OpenAI-compatible | `Ask::Auth.resolve(:openai_api_key)` | `Ask::
|
|
11
|
-
| **Anthropic** (Claude) | `Ask::Auth.resolve(:anthropic_api_key)` | `Ask::
|
|
12
|
-
| **Google Gemini** | `Ask::Auth.resolve(:gemini_api_key)` | `Ask::
|
|
13
|
-
| **Vertex AI** | GCP service account | `Ask::
|
|
14
|
-
| **Amazon Bedrock** | AWS credentials chain | `Ask::
|
|
15
|
-
| **Ollama** (local) | None needed | `Ask::
|
|
16
|
-
| **Mistral AI** | `Ask::Auth.resolve(:mistral_api_key)` | `Ask::
|
|
17
|
-
| **Cloudflare Workers AI** | `Ask::Auth.resolve(:cloudflare_api_key)` | `Ask::
|
|
10
|
+
| **OpenAI** + all OpenAI-compatible | `Ask::Auth.resolve(:openai_api_key)` | `Ask::Providers::OpenAI` |
|
|
11
|
+
| **Anthropic** (Claude) | `Ask::Auth.resolve(:anthropic_api_key)` | `Ask::Providers::Anthropic` |
|
|
12
|
+
| **Google Gemini** | `Ask::Auth.resolve(:gemini_api_key)` | `Ask::Providers::Google` |
|
|
13
|
+
| **Vertex AI** | GCP service account | `Ask::Providers::Google` (via Vertex) |
|
|
14
|
+
| **Amazon Bedrock** | AWS credentials chain | `Ask::Providers::Bedrock` |
|
|
15
|
+
| **Ollama** (local) | None needed | `Ask::Providers::Ollama` |
|
|
16
|
+
| **Mistral AI** | `Ask::Auth.resolve(:mistral_api_key)` | `Ask::Providers::Mistral` |
|
|
17
|
+
| **Cloudflare Workers AI** | `Ask::Auth.resolve(:cloudflare_api_key)` | `Ask::Providers::Cloudflare` |
|
|
18
18
|
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
@@ -32,7 +32,7 @@ models = Ask::Models.find("gpt-4o")
|
|
|
32
32
|
# => { provider: :openai, capabilities: [...] }
|
|
33
33
|
|
|
34
34
|
# Use a provider directly
|
|
35
|
-
provider = Ask::
|
|
35
|
+
provider = Ask::Providers::OpenAI.new
|
|
36
36
|
provider.chat(conversation, tools: [], model: "gpt-4o") do |chunk|
|
|
37
37
|
print chunk.content
|
|
38
38
|
end
|
|
@@ -43,21 +43,75 @@ end
|
|
|
43
43
|
Each provider and model exposes its capabilities:
|
|
44
44
|
|
|
45
45
|
```ruby
|
|
46
|
-
provider = Ask::
|
|
46
|
+
provider = Ask::Providers::OpenAI.new
|
|
47
47
|
provider.capabilities
|
|
48
|
-
# =>
|
|
48
|
+
# => { chat: true, streaming: true, tool_calls: true, vision: true, thinking: true,
|
|
49
49
|
# :structured_output, :embed, :transcribe, :paint, :moderate]
|
|
50
50
|
|
|
51
51
|
model = Ask::Models.find("claude-sonnet-4-5")
|
|
52
52
|
model[:capabilities]
|
|
53
|
-
# =>
|
|
53
|
+
# => { chat: true, streaming: true, tool_calls: true, vision: true, thinking: true, :prompt_caching]
|
|
54
54
|
|
|
55
55
|
# Unsupported capabilities raise a helpful error
|
|
56
|
-
provider = Ask::
|
|
56
|
+
provider = Ask::Providers::Anthropic.new
|
|
57
57
|
provider.embed(["text"], model: "claude-sonnet-4-5")
|
|
58
58
|
# => Ask::CapabilityNotSupported: Anthropic (claude-sonnet-4-5) does not support embeddings.
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
## Streaming
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
stream = provider.chat(
|
|
67
|
+
[{ role: "user", content: "Tell me a story" }],
|
|
68
|
+
model: "gpt-4o",
|
|
69
|
+
stream: true
|
|
70
|
+
) do |chunk|
|
|
71
|
+
print chunk.content
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# After streaming completes, you can access the full response
|
|
75
|
+
puts stream.accumulated_text
|
|
76
|
+
puts stream.accumulated_usage
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Tool Calls
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
tools = [{
|
|
83
|
+
name: "get_weather",
|
|
84
|
+
description: "Get weather for a location",
|
|
85
|
+
parameters: {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: { location: { type: "string" } },
|
|
88
|
+
required: ["location"]
|
|
89
|
+
}
|
|
90
|
+
}]
|
|
91
|
+
|
|
92
|
+
response = provider.chat(
|
|
93
|
+
[{ role: "user", content: "What's the weather in NYC?" }],
|
|
94
|
+
model: "gpt-4o",
|
|
95
|
+
tools: tools
|
|
96
|
+
)
|
|
97
|
+
# response.tool_call? => true
|
|
98
|
+
# response.tool_calls => [{ id: "call_1", name: "get_weather", arguments: '{"location":"NYC"}' }]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Error Handling
|
|
102
|
+
|
|
103
|
+
Provider errors map to structured `Ask::Error` types:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
Ask::RateLimitError # 429 — retry with backoff
|
|
107
|
+
Ask::Unauthorized # 401/403 — check your API key
|
|
108
|
+
Ask::ServerError # 500 — provider issue
|
|
109
|
+
Ask::ServiceUnavailable # 503 — temporary
|
|
110
|
+
Ask::ContextLengthExceeded # context window exceeded
|
|
111
|
+
Ask::ProviderError # other provider errors
|
|
112
|
+
Ask::CapabilityNotSupported # feature not available on this model
|
|
113
|
+
```
|
|
114
|
+
|
|
61
115
|
## Development
|
|
62
116
|
|
|
63
117
|
```bash
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Model definitions for OpenAI and compatible providers.
|
|
4
|
+
# Registered on gem load via Ask::Models.register.
|
|
5
|
+
module Ask
|
|
6
|
+
module LLM
|
|
7
|
+
module Models
|
|
8
|
+
OPENAI_MODELS = [
|
|
9
|
+
{ id: "gpt-4o", family: "gpt4o", capabilities: %w[chat streaming function_calling structured_output vision], context: 128000, output: 16384 },
|
|
10
|
+
{ id: "gpt-4o-mini", family: "gpt4o_mini", capabilities: %w[chat streaming function_calling structured_output vision], context: 128000, output: 16384 },
|
|
11
|
+
{ id: "gpt-4.1", family: "gpt41", capabilities: %w[chat streaming function_calling structured_output vision], context: 1047576, output: 32768 },
|
|
12
|
+
{ id: "gpt-4.1-mini", family: "gpt41_mini", capabilities: %w[chat streaming function_calling structured_output vision], context: 1047576, output: 32768 },
|
|
13
|
+
{ id: "gpt-4.1-nano", family: "gpt41_nano", capabilities: %w[chat streaming function_calling structured_output vision], context: 1047576, output: 32768 },
|
|
14
|
+
{ id: "gpt-4-turbo", family: "gpt4_turbo", capabilities: %w[chat streaming function_calling vision], context: 128000, output: 4096 },
|
|
15
|
+
{ id: "gpt-4", family: "gpt4", capabilities: %w[chat streaming function_calling], context: 8192, output: 8192 },
|
|
16
|
+
{ id: "o1", family: "o1", capabilities: %w[chat streaming function_calling structured_output reasoning], context: 200000, output: 100000 },
|
|
17
|
+
{ id: "o1-mini", family: "o1_mini", capabilities: %w[chat streaming function_calling reasoning], context: 128000, output: 65536 },
|
|
18
|
+
{ id: "o3-mini", family: "o3_mini", capabilities: %w[chat streaming function_calling structured_output reasoning], context: 200000, output: 100000 },
|
|
19
|
+
{ id: "gpt-4o-audio-preview", family: "gpt4o_audio", capabilities: %w[chat streaming audio], context: 128000 },
|
|
20
|
+
{ id: "gpt-4o-realtime-preview", family: "gpt4o_realtime", capabilities: %w[chat streaming audio], context: 128000 },
|
|
21
|
+
{ id: "gpt-4o-mini-realtime-preview", family: "gpt4o_mini_realtime", capabilities: %w[chat streaming audio], context: 128000 },
|
|
22
|
+
{ id: "gpt-4.5-preview", family: "gpt45", capabilities: %w[chat streaming function_calling structured_output vision], context: 128000, output: 16384 },
|
|
23
|
+
{ id: "text-embedding-3-large", family: "embedding3_large", capabilities: %w[embed], context: 8191 },
|
|
24
|
+
{ id: "text-embedding-3-small", family: "embedding3_small", capabilities: %w[embed], context: 8191 },
|
|
25
|
+
{ id: "whisper-1", family: "whisper", capabilities: %w[transcribe] },
|
|
26
|
+
{ id: "tts-1", family: "tts1", capabilities: %w[tts] },
|
|
27
|
+
{ id: "tts-1-hd", family: "tts1_hd", capabilities: %w[tts] },
|
|
28
|
+
{ id: "dall-e-3", family: "dall_e", capabilities: %w[paint] },
|
|
29
|
+
{ id: "dall-e-2", family: "dall_e", capabilities: %w[paint] }
|
|
30
|
+
].freeze
|
|
31
|
+
|
|
32
|
+
ANTHROPIC_MODELS = [
|
|
33
|
+
{ id: "claude-sonnet-4-5", family: "claude_sonnet", capabilities: %w[chat streaming function_calling vision thinking prompt_caching], context: 200000, output: 8192 },
|
|
34
|
+
{ id: "claude-sonnet-4", family: "claude_sonnet", capabilities: %w[chat streaming function_calling vision thinking prompt_caching], context: 200000, output: 8192 },
|
|
35
|
+
{ id: "claude-4-opus", family: "claude_opus", capabilities: %w[chat streaming function_calling vision thinking prompt_caching], context: 200000, output: 8192 },
|
|
36
|
+
{ id: "claude-3.5-sonnet", family: "claude_sonnet", capabilities: %w[chat streaming function_calling vision thinking], context: 200000, output: 8192 },
|
|
37
|
+
{ id: "claude-3.5-haiku", family: "claude_haiku", capabilities: %w[chat streaming function_calling vision thinking], context: 200000, output: 8192 },
|
|
38
|
+
{ id: "claude-3-opus", family: "claude_opus", capabilities: %w[chat streaming function_calling vision thinking], context: 200000, output: 4096 },
|
|
39
|
+
{ id: "claude-3-sonnet", family: "claude_sonnet", capabilities: %w[chat streaming function_calling vision], context: 200000, output: 4096 },
|
|
40
|
+
{ id: "claude-3-haiku", family: "claude_haiku", capabilities: %w[chat streaming function_calling vision], context: 200000, output: 4096 }
|
|
41
|
+
].freeze
|
|
42
|
+
|
|
43
|
+
GOOGLE_MODELS = [
|
|
44
|
+
{ id: "gemini-2.5-pro", family: "gemini", capabilities: %w[chat streaming function_calling structured_output vision reasoning], context: 1048576, output: 65536 },
|
|
45
|
+
{ id: "gemini-2.5-flash", family: "gemini", capabilities: %w[chat streaming function_calling structured_output vision], context: 1048576, output: 65536 },
|
|
46
|
+
{ id: "gemini-2.0-flash", family: "gemini", capabilities: %w[chat streaming function_calling structured_output vision], context: 1048576, output: 8192 },
|
|
47
|
+
{ id: "gemini-1.5-pro", family: "gemini", capabilities: %w[chat streaming function_calling structured_output vision], context: 2097152, output: 8192 },
|
|
48
|
+
{ id: "gemini-1.5-flash", family: "gemini", capabilities: %w[chat streaming function_calling structured_output vision], context: 1048576, output: 8192 },
|
|
49
|
+
{ id: "text-embedding-004", family: "embedding", capabilities: %w[embed], context: 2048 }
|
|
50
|
+
].freeze
|
|
51
|
+
|
|
52
|
+
MISTRAL_MODELS = [
|
|
53
|
+
{ id: "mistral-large-2501", family: "mistral", capabilities: %w[chat streaming function_calling structured_output], context: 128000, output: 4096 },
|
|
54
|
+
{ id: "mistral-small-2501", family: "mistral", capabilities: %w[chat streaming function_calling structured_output], context: 128000, output: 4096 },
|
|
55
|
+
{ id: "mistral-embed", family: "mistral", capabilities: %w[embed], context: 8192 }
|
|
56
|
+
].freeze
|
|
57
|
+
|
|
58
|
+
OLLAMA_MODELS = [
|
|
59
|
+
{ id: "llama3.2", family: "llama", capabilities: %w[chat streaming], context: 8192 },
|
|
60
|
+
{ id: "llama3.3", family: "llama", capabilities: %w[chat streaming], context: 8192 },
|
|
61
|
+
{ id: "mistral", family: "mistral", capabilities: %w[chat streaming], context: 8192 },
|
|
62
|
+
{ id: "gemma3", family: "gemma", capabilities: %w[chat streaming], context: 8192 },
|
|
63
|
+
{ id: "phi4", family: "phi", capabilities: %w[chat streaming], context: 8192 },
|
|
64
|
+
{ id: "qwen2.5", family: "qwen", capabilities: %w[chat streaming], context: 32768 },
|
|
65
|
+
{ id: "deepseek-r1", family: "deepseek", capabilities: %w[chat streaming reasoning], context: 8192 }
|
|
66
|
+
].freeze
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
data/lib/ask/llm/version.rb
CHANGED
data/lib/ask/provider/bedrock.rb
CHANGED
|
@@ -25,7 +25,7 @@ module Ask
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def embed(_texts, model: nil)
|
|
28
|
-
raise Ask::
|
|
28
|
+
raise Ask::CapabilityNotSupported, "Bedrock does not support embeddings via Converse API"
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def list_models
|
data/lib/ask/provider/openai.rb
CHANGED
|
@@ -51,13 +51,13 @@ module Ask
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
class << self
|
|
54
|
-
def slug; "openai"; end
|
|
55
|
-
|
|
54
|
+
def slug; "openai"; end
|
|
55
|
+
def capabilities
|
|
56
56
|
{ chat: true, streaming: true, tool_calls: true, vision: true, thinking: true, structured_output: true, embed: true, transcribe: true, paint: true, moderate: true }
|
|
57
57
|
end
|
|
58
58
|
def configuration_options; %i[api_key base_url organization_id project_id]; end
|
|
59
59
|
def configuration_requirements; %i[api_key]; end
|
|
60
|
-
|
|
60
|
+
def configured?(config)
|
|
61
61
|
(config.respond_to?(:api_key) && !config.api_key.to_s.empty?) ||
|
|
62
62
|
(config.respond_to?(:openai_api_key) && !config.openai_api_key.to_s.empty?)
|
|
63
63
|
end
|
data/lib/ask-llm-providers.rb
CHANGED
|
@@ -10,6 +10,7 @@ require "base64"
|
|
|
10
10
|
# Common infrastructure
|
|
11
11
|
require_relative "ask/llm/config"
|
|
12
12
|
require_relative "ask/llm/http"
|
|
13
|
+
require_relative "ask/llm/models/openai"
|
|
13
14
|
|
|
14
15
|
# Load providers
|
|
15
16
|
require_relative "ask/provider/openai"
|
|
@@ -28,3 +29,21 @@ Ask::Provider.register(:bedrock, Ask::Providers::Bedrock)
|
|
|
28
29
|
Ask::Provider.register(:ollama, Ask::Providers::Ollama)
|
|
29
30
|
Ask::Provider.register(:mistral, Ask::Providers::Mistral)
|
|
30
31
|
Ask::Provider.register(:cloudflare, Ask::Providers::Cloudflare)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Register known models for each provider in the catalog
|
|
35
|
+
[
|
|
36
|
+
[Ask::Providers::OpenAI, Ask::LLM::Models::OPENAI_MODELS],
|
|
37
|
+
[Ask::Providers::Anthropic, Ask::LLM::Models::ANTHROPIC_MODELS],
|
|
38
|
+
[Ask::Providers::Google, Ask::LLM::Models::GOOGLE_MODELS],
|
|
39
|
+
[Ask::Providers::Mistral, Ask::LLM::Models::MISTRAL_MODELS],
|
|
40
|
+
[Ask::Providers::Ollama, Ask::LLM::Models::OLLAMA_MODELS]
|
|
41
|
+
].each do |provider, models|
|
|
42
|
+
models.each do |m|
|
|
43
|
+
Ask::ModelCatalog.instance.register(Ask::ModelInfo.new(
|
|
44
|
+
id: m[:id], provider: provider.slug, family: m[:family],
|
|
45
|
+
capabilities: m[:capabilities],
|
|
46
|
+
context_window: m[:context], max_output_tokens: m[:output]
|
|
47
|
+
))
|
|
48
|
+
end
|
|
49
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ask-llm-providers
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kaka Ruto
|
|
@@ -13,16 +13,16 @@ dependencies:
|
|
|
13
13
|
name: ask-core
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
15
15
|
requirements:
|
|
16
|
-
- - "
|
|
16
|
+
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
18
|
+
version: 0.1.1
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
|
-
- - "
|
|
23
|
+
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version:
|
|
25
|
+
version: 0.1.1
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: ask-auth
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -79,6 +79,20 @@ dependencies:
|
|
|
79
79
|
- - ">="
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
81
|
version: '0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: base64
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0.2'
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0.2'
|
|
82
96
|
- !ruby/object:Gem::Dependency
|
|
83
97
|
name: minitest
|
|
84
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -163,6 +177,7 @@ files:
|
|
|
163
177
|
- lib/ask-llm-providers.rb
|
|
164
178
|
- lib/ask/llm/config.rb
|
|
165
179
|
- lib/ask/llm/http.rb
|
|
180
|
+
- lib/ask/llm/models/openai.rb
|
|
166
181
|
- lib/ask/llm/version.rb
|
|
167
182
|
- lib/ask/provider/anthropic.rb
|
|
168
183
|
- lib/ask/provider/bedrock.rb
|