ruby_llm_swarm 1.9.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +175 -0
- data/lib/generators/ruby_llm/chat_ui/chat_ui_generator.rb +187 -0
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/chats_controller.rb.tt +39 -0
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/messages_controller.rb.tt +24 -0
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/models_controller.rb.tt +14 -0
- data/lib/generators/ruby_llm/chat_ui/templates/jobs/chat_response_job.rb.tt +12 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_chat.html.erb.tt +16 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_form.html.erb.tt +29 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/index.html.erb.tt +16 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/new.html.erb.tt +11 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/show.html.erb.tt +23 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_content.html.erb.tt +1 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_form.html.erb.tt +21 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_message.html.erb.tt +13 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_tool_calls.html.erb.tt +7 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt +9 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/_model.html.erb.tt +16 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/index.html.erb.tt +28 -0
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/show.html.erb.tt +18 -0
- data/lib/generators/ruby_llm/generator_helpers.rb +194 -0
- data/lib/generators/ruby_llm/install/install_generator.rb +106 -0
- data/lib/generators/ruby_llm/install/templates/add_references_to_chats_tool_calls_and_messages_migration.rb.tt +9 -0
- data/lib/generators/ruby_llm/install/templates/chat_model.rb.tt +3 -0
- data/lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt +7 -0
- data/lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt +16 -0
- data/lib/generators/ruby_llm/install/templates/create_models_migration.rb.tt +45 -0
- data/lib/generators/ruby_llm/install/templates/create_tool_calls_migration.rb.tt +20 -0
- data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +12 -0
- data/lib/generators/ruby_llm/install/templates/message_model.rb.tt +4 -0
- data/lib/generators/ruby_llm/install/templates/model_model.rb.tt +3 -0
- data/lib/generators/ruby_llm/install/templates/tool_call_model.rb.tt +3 -0
- data/lib/generators/ruby_llm/upgrade_to_v1_7/templates/migration.rb.tt +145 -0
- data/lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +124 -0
- data/lib/generators/ruby_llm/upgrade_to_v1_9/templates/add_v1_9_message_columns.rb.tt +15 -0
- data/lib/generators/ruby_llm/upgrade_to_v1_9/upgrade_to_v1_9_generator.rb +49 -0
- data/lib/ruby_llm/active_record/acts_as.rb +174 -0
- data/lib/ruby_llm/active_record/acts_as_legacy.rb +384 -0
- data/lib/ruby_llm/active_record/chat_methods.rb +350 -0
- data/lib/ruby_llm/active_record/message_methods.rb +81 -0
- data/lib/ruby_llm/active_record/model_methods.rb +84 -0
- data/lib/ruby_llm/aliases.json +295 -0
- data/lib/ruby_llm/aliases.rb +38 -0
- data/lib/ruby_llm/attachment.rb +220 -0
- data/lib/ruby_llm/chat.rb +816 -0
- data/lib/ruby_llm/chunk.rb +6 -0
- data/lib/ruby_llm/configuration.rb +78 -0
- data/lib/ruby_llm/connection.rb +126 -0
- data/lib/ruby_llm/content.rb +73 -0
- data/lib/ruby_llm/context.rb +29 -0
- data/lib/ruby_llm/embedding.rb +29 -0
- data/lib/ruby_llm/error.rb +84 -0
- data/lib/ruby_llm/image.rb +49 -0
- data/lib/ruby_llm/message.rb +86 -0
- data/lib/ruby_llm/mime_type.rb +71 -0
- data/lib/ruby_llm/model/info.rb +111 -0
- data/lib/ruby_llm/model/modalities.rb +22 -0
- data/lib/ruby_llm/model/pricing.rb +48 -0
- data/lib/ruby_llm/model/pricing_category.rb +46 -0
- data/lib/ruby_llm/model/pricing_tier.rb +33 -0
- data/lib/ruby_llm/model.rb +7 -0
- data/lib/ruby_llm/models.json +33198 -0
- data/lib/ruby_llm/models.rb +231 -0
- data/lib/ruby_llm/models_schema.json +168 -0
- data/lib/ruby_llm/moderation.rb +56 -0
- data/lib/ruby_llm/provider.rb +243 -0
- data/lib/ruby_llm/providers/anthropic/capabilities.rb +134 -0
- data/lib/ruby_llm/providers/anthropic/chat.rb +125 -0
- data/lib/ruby_llm/providers/anthropic/content.rb +44 -0
- data/lib/ruby_llm/providers/anthropic/embeddings.rb +20 -0
- data/lib/ruby_llm/providers/anthropic/media.rb +92 -0
- data/lib/ruby_llm/providers/anthropic/models.rb +63 -0
- data/lib/ruby_llm/providers/anthropic/streaming.rb +45 -0
- data/lib/ruby_llm/providers/anthropic/tools.rb +109 -0
- data/lib/ruby_llm/providers/anthropic.rb +36 -0
- data/lib/ruby_llm/providers/bedrock/capabilities.rb +167 -0
- data/lib/ruby_llm/providers/bedrock/chat.rb +63 -0
- data/lib/ruby_llm/providers/bedrock/media.rb +61 -0
- data/lib/ruby_llm/providers/bedrock/models.rb +98 -0
- data/lib/ruby_llm/providers/bedrock/signing.rb +831 -0
- data/lib/ruby_llm/providers/bedrock/streaming/base.rb +51 -0
- data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +71 -0
- data/lib/ruby_llm/providers/bedrock/streaming/message_processing.rb +67 -0
- data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +80 -0
- data/lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb +78 -0
- data/lib/ruby_llm/providers/bedrock/streaming.rb +18 -0
- data/lib/ruby_llm/providers/bedrock.rb +82 -0
- data/lib/ruby_llm/providers/deepseek/capabilities.rb +130 -0
- data/lib/ruby_llm/providers/deepseek/chat.rb +16 -0
- data/lib/ruby_llm/providers/deepseek.rb +30 -0
- data/lib/ruby_llm/providers/gemini/capabilities.rb +281 -0
- data/lib/ruby_llm/providers/gemini/chat.rb +454 -0
- data/lib/ruby_llm/providers/gemini/embeddings.rb +37 -0
- data/lib/ruby_llm/providers/gemini/images.rb +47 -0
- data/lib/ruby_llm/providers/gemini/media.rb +112 -0
- data/lib/ruby_llm/providers/gemini/models.rb +40 -0
- data/lib/ruby_llm/providers/gemini/streaming.rb +61 -0
- data/lib/ruby_llm/providers/gemini/tools.rb +198 -0
- data/lib/ruby_llm/providers/gemini/transcription.rb +116 -0
- data/lib/ruby_llm/providers/gemini.rb +37 -0
- data/lib/ruby_llm/providers/gpustack/chat.rb +27 -0
- data/lib/ruby_llm/providers/gpustack/media.rb +46 -0
- data/lib/ruby_llm/providers/gpustack/models.rb +90 -0
- data/lib/ruby_llm/providers/gpustack.rb +34 -0
- data/lib/ruby_llm/providers/mistral/capabilities.rb +155 -0
- data/lib/ruby_llm/providers/mistral/chat.rb +24 -0
- data/lib/ruby_llm/providers/mistral/embeddings.rb +33 -0
- data/lib/ruby_llm/providers/mistral/models.rb +48 -0
- data/lib/ruby_llm/providers/mistral.rb +32 -0
- data/lib/ruby_llm/providers/ollama/chat.rb +27 -0
- data/lib/ruby_llm/providers/ollama/media.rb +46 -0
- data/lib/ruby_llm/providers/ollama/models.rb +36 -0
- data/lib/ruby_llm/providers/ollama.rb +30 -0
- data/lib/ruby_llm/providers/openai/capabilities.rb +299 -0
- data/lib/ruby_llm/providers/openai/chat.rb +88 -0
- data/lib/ruby_llm/providers/openai/embeddings.rb +33 -0
- data/lib/ruby_llm/providers/openai/images.rb +38 -0
- data/lib/ruby_llm/providers/openai/media.rb +81 -0
- data/lib/ruby_llm/providers/openai/models.rb +39 -0
- data/lib/ruby_llm/providers/openai/moderation.rb +34 -0
- data/lib/ruby_llm/providers/openai/streaming.rb +46 -0
- data/lib/ruby_llm/providers/openai/tools.rb +98 -0
- data/lib/ruby_llm/providers/openai/transcription.rb +70 -0
- data/lib/ruby_llm/providers/openai.rb +44 -0
- data/lib/ruby_llm/providers/openai_responses.rb +395 -0
- data/lib/ruby_llm/providers/openrouter/models.rb +73 -0
- data/lib/ruby_llm/providers/openrouter.rb +26 -0
- data/lib/ruby_llm/providers/perplexity/capabilities.rb +137 -0
- data/lib/ruby_llm/providers/perplexity/chat.rb +16 -0
- data/lib/ruby_llm/providers/perplexity/models.rb +42 -0
- data/lib/ruby_llm/providers/perplexity.rb +48 -0
- data/lib/ruby_llm/providers/vertexai/chat.rb +14 -0
- data/lib/ruby_llm/providers/vertexai/embeddings.rb +32 -0
- data/lib/ruby_llm/providers/vertexai/models.rb +130 -0
- data/lib/ruby_llm/providers/vertexai/streaming.rb +14 -0
- data/lib/ruby_llm/providers/vertexai/transcription.rb +16 -0
- data/lib/ruby_llm/providers/vertexai.rb +55 -0
- data/lib/ruby_llm/railtie.rb +35 -0
- data/lib/ruby_llm/responses_session.rb +77 -0
- data/lib/ruby_llm/stream_accumulator.rb +101 -0
- data/lib/ruby_llm/streaming.rb +153 -0
- data/lib/ruby_llm/tool.rb +209 -0
- data/lib/ruby_llm/tool_call.rb +22 -0
- data/lib/ruby_llm/tool_executors.rb +125 -0
- data/lib/ruby_llm/transcription.rb +35 -0
- data/lib/ruby_llm/utils.rb +91 -0
- data/lib/ruby_llm/version.rb +5 -0
- data/lib/ruby_llm.rb +140 -0
- data/lib/tasks/models.rake +525 -0
- data/lib/tasks/release.rake +67 -0
- data/lib/tasks/ruby_llm.rake +15 -0
- data/lib/tasks/vcr.rake +92 -0
- metadata +346 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
class Mistral
|
|
6
|
+
# Determines capabilities for Mistral models
|
|
7
|
+
module Capabilities
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def supports_streaming?(model_id)
|
|
11
|
+
!model_id.match?(/embed|moderation|ocr|transcriptions/)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def supports_tools?(model_id)
|
|
15
|
+
!model_id.match?(/embed|moderation|ocr|voxtral|transcriptions|mistral-(tiny|small)-(2312|2402)/)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def supports_vision?(model_id)
|
|
19
|
+
model_id.match?(/pixtral|mistral-small-(2503|2506)|mistral-medium/)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def supports_json_mode?(model_id)
|
|
23
|
+
!model_id.match?(/embed|moderation|ocr|voxtral|transcriptions/) && supports_tools?(model_id)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def format_display_name(model_id)
|
|
27
|
+
case model_id
|
|
28
|
+
when /mistral-large/ then 'Mistral Large'
|
|
29
|
+
when /mistral-medium/ then 'Mistral Medium'
|
|
30
|
+
when /mistral-small/ then 'Mistral Small'
|
|
31
|
+
when /ministral-3b/ then 'Ministral 3B'
|
|
32
|
+
when /ministral-8b/ then 'Ministral 8B'
|
|
33
|
+
when /codestral/ then 'Codestral'
|
|
34
|
+
when /pixtral-large/ then 'Pixtral Large'
|
|
35
|
+
when /pixtral-12b/ then 'Pixtral 12B'
|
|
36
|
+
when /mistral-embed/ then 'Mistral Embed'
|
|
37
|
+
when /mistral-moderation/ then 'Mistral Moderation'
|
|
38
|
+
else model_id.split('-').map(&:capitalize).join(' ')
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def model_family(model_id)
|
|
43
|
+
case model_id
|
|
44
|
+
when /mistral-large/ then 'mistral-large'
|
|
45
|
+
when /mistral-medium/ then 'mistral-medium'
|
|
46
|
+
when /mistral-small/ then 'mistral-small'
|
|
47
|
+
when /ministral/ then 'ministral'
|
|
48
|
+
when /codestral/ then 'codestral'
|
|
49
|
+
when /pixtral/ then 'pixtral'
|
|
50
|
+
when /mistral-embed/ then 'mistral-embed'
|
|
51
|
+
when /mistral-moderation/ then 'mistral-moderation'
|
|
52
|
+
else 'mistral'
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def context_window_for(_model_id)
|
|
57
|
+
32_768
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def max_tokens_for(_model_id)
|
|
61
|
+
8192
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def modalities_for(model_id)
|
|
65
|
+
case model_id
|
|
66
|
+
when /pixtral/
|
|
67
|
+
{
|
|
68
|
+
input: %w[text image],
|
|
69
|
+
output: ['text']
|
|
70
|
+
}
|
|
71
|
+
when /embed/
|
|
72
|
+
{
|
|
73
|
+
input: ['text'],
|
|
74
|
+
output: ['embeddings']
|
|
75
|
+
}
|
|
76
|
+
else
|
|
77
|
+
{
|
|
78
|
+
input: ['text'],
|
|
79
|
+
output: ['text']
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def capabilities_for(model_id) # rubocop:disable Metrics/PerceivedComplexity
|
|
85
|
+
case model_id
|
|
86
|
+
when /moderation/ then ['moderation']
|
|
87
|
+
when /voxtral.*transcribe/ then ['transcription']
|
|
88
|
+
when /ocr/ then ['vision']
|
|
89
|
+
else
|
|
90
|
+
capabilities = []
|
|
91
|
+
capabilities << 'streaming' if supports_streaming?(model_id)
|
|
92
|
+
capabilities << 'function_calling' if supports_tools?(model_id)
|
|
93
|
+
capabilities << 'structured_output' if supports_json_mode?(model_id)
|
|
94
|
+
capabilities << 'vision' if supports_vision?(model_id)
|
|
95
|
+
|
|
96
|
+
capabilities << 'reasoning' if model_id.match?(/magistral/)
|
|
97
|
+
capabilities << 'batch' unless model_id.match?(/voxtral|ocr|embed|moderation/)
|
|
98
|
+
capabilities << 'fine_tuning' if model_id.match?(/mistral-(small|medium|large)|devstral/)
|
|
99
|
+
capabilities << 'distillation' if model_id.match?(/ministral/)
|
|
100
|
+
capabilities << 'predicted_outputs' if model_id.match?(/codestral/)
|
|
101
|
+
|
|
102
|
+
capabilities.uniq
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def pricing_for(_model_id)
|
|
107
|
+
{
|
|
108
|
+
input: 0.0,
|
|
109
|
+
output: 0.0
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def release_date_for(model_id)
|
|
114
|
+
case model_id
|
|
115
|
+
when 'open-mistral-7b', 'mistral-tiny' then '2023-09-27'
|
|
116
|
+
when 'mistral-medium-2312', 'mistral-small-2312', 'mistral-small',
|
|
117
|
+
'open-mixtral-8x7b', 'mistral-tiny-2312' then '2023-12-11'
|
|
118
|
+
|
|
119
|
+
when 'mistral-embed' then '2024-01-11'
|
|
120
|
+
when 'mistral-large-2402', 'mistral-small-2402' then '2024-02-26'
|
|
121
|
+
when 'open-mixtral-8x22b', 'open-mixtral-8x22b-2404' then '2024-04-17'
|
|
122
|
+
when 'codestral-2405' then '2024-05-22'
|
|
123
|
+
when 'codestral-mamba-2407', 'codestral-mamba-latest', 'open-codestral-mamba' then '2024-07-16'
|
|
124
|
+
when 'open-mistral-nemo', 'open-mistral-nemo-2407', 'mistral-tiny-2407',
|
|
125
|
+
'mistral-tiny-latest' then '2024-07-18'
|
|
126
|
+
when 'mistral-large-2407' then '2024-07-24'
|
|
127
|
+
when 'pixtral-12b-2409', 'pixtral-12b-latest', 'pixtral-12b' then '2024-09-17'
|
|
128
|
+
when 'mistral-small-2409' then '2024-09-18'
|
|
129
|
+
when 'ministral-3b-2410', 'ministral-3b-latest', 'ministral-8b-2410',
|
|
130
|
+
'ministral-8b-latest' then '2024-10-16'
|
|
131
|
+
when 'pixtral-large-2411', 'pixtral-large-latest', 'mistral-large-pixtral-2411' then '2024-11-12'
|
|
132
|
+
when 'mistral-large-2411', 'mistral-large-latest', 'mistral-large' then '2024-11-20'
|
|
133
|
+
when 'codestral-2411-rc5', 'mistral-moderation-2411', 'mistral-moderation-latest' then '2024-11-26'
|
|
134
|
+
when 'codestral-2412' then '2024-12-17'
|
|
135
|
+
|
|
136
|
+
when 'mistral-small-2501' then '2025-01-13'
|
|
137
|
+
when 'codestral-2501' then '2025-01-14'
|
|
138
|
+
when 'mistral-saba-2502', 'mistral-saba-latest' then '2025-02-18'
|
|
139
|
+
when 'mistral-small-2503' then '2025-03-03'
|
|
140
|
+
when 'mistral-ocr-2503' then '2025-03-21'
|
|
141
|
+
when 'mistral-medium', 'mistral-medium-latest', 'mistral-medium-2505' then '2025-05-06'
|
|
142
|
+
when 'codestral-embed', 'codestral-embed-2505' then '2025-05-21'
|
|
143
|
+
when 'mistral-ocr-2505', 'mistral-ocr-latest' then '2025-05-23'
|
|
144
|
+
when 'devstral-small-2505' then '2025-05-28'
|
|
145
|
+
when 'mistral-small-2506', 'mistral-small-latest', 'magistral-medium-2506',
|
|
146
|
+
'magistral-medium-latest' then '2025-06-10'
|
|
147
|
+
when 'devstral-small-2507', 'devstral-small-latest', 'devstral-medium-2507',
|
|
148
|
+
'devstral-medium-latest' then '2025-07-09'
|
|
149
|
+
when 'codestral-2508', 'codestral-latest' then '2025-08-30'
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
class Mistral
|
|
6
|
+
# Chat methods for Mistral API
|
|
7
|
+
module Chat
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def format_role(role)
|
|
11
|
+
role.to_s
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# rubocop:disable Metrics/ParameterLists
|
|
15
|
+
def render_payload(messages, tools:, temperature:, model:, stream: false, schema: nil)
|
|
16
|
+
payload = super
|
|
17
|
+
payload.delete(:stream_options)
|
|
18
|
+
payload
|
|
19
|
+
end
|
|
20
|
+
# rubocop:enable Metrics/ParameterLists
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
class Mistral
|
|
6
|
+
# Embeddings methods for Mistral API
|
|
7
|
+
module Embeddings
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def embedding_url(...)
|
|
11
|
+
'embeddings'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render_embedding_payload(text, model:, dimensions:) # rubocop:disable Lint/UnusedMethodArgument
|
|
15
|
+
{
|
|
16
|
+
model: model,
|
|
17
|
+
input: text
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def parse_embedding_response(response, model:, text:)
|
|
22
|
+
data = response.body
|
|
23
|
+
input_tokens = data.dig('usage', 'prompt_tokens') || 0
|
|
24
|
+
vectors = data['data'].map { |d| d['embedding'] }
|
|
25
|
+
|
|
26
|
+
vectors = vectors.first if vectors.length == 1 && !text.is_a?(Array)
|
|
27
|
+
|
|
28
|
+
Embedding.new(vectors:, model:, input_tokens:)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
class Mistral
|
|
6
|
+
# Model information for Mistral
|
|
7
|
+
module Models
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def models_url
|
|
11
|
+
'models'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def headers(config)
|
|
15
|
+
{
|
|
16
|
+
'Authorization' => "Bearer #{config.mistral_api_key}"
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def parse_list_models_response(response, slug, capabilities)
|
|
21
|
+
Array(response.body['data']).map do |model_data|
|
|
22
|
+
model_id = model_data['id']
|
|
23
|
+
|
|
24
|
+
release_date = capabilities.release_date_for(model_id)
|
|
25
|
+
created_at = release_date ? Time.parse(release_date) : nil
|
|
26
|
+
|
|
27
|
+
Model::Info.new(
|
|
28
|
+
id: model_id,
|
|
29
|
+
name: capabilities.format_display_name(model_id),
|
|
30
|
+
provider: slug,
|
|
31
|
+
family: capabilities.model_family(model_id),
|
|
32
|
+
created_at: created_at,
|
|
33
|
+
context_window: capabilities.context_window_for(model_id),
|
|
34
|
+
max_output_tokens: capabilities.max_tokens_for(model_id),
|
|
35
|
+
modalities: capabilities.modalities_for(model_id),
|
|
36
|
+
capabilities: capabilities.capabilities_for(model_id),
|
|
37
|
+
pricing: capabilities.pricing_for(model_id),
|
|
38
|
+
metadata: {
|
|
39
|
+
object: model_data['object'],
|
|
40
|
+
owned_by: model_data['owned_by']
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
# Mistral API integration.
|
|
6
|
+
class Mistral < OpenAI
|
|
7
|
+
include Mistral::Chat
|
|
8
|
+
include Mistral::Models
|
|
9
|
+
include Mistral::Embeddings
|
|
10
|
+
|
|
11
|
+
def api_base
|
|
12
|
+
'https://api.mistral.ai/v1'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def headers
|
|
16
|
+
{
|
|
17
|
+
'Authorization' => "Bearer #{@config.mistral_api_key}"
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
def capabilities
|
|
23
|
+
Mistral::Capabilities
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def configuration_requirements
|
|
27
|
+
%i[mistral_api_key]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
class Ollama
|
|
6
|
+
# Chat methods of the Ollama API integration
|
|
7
|
+
module Chat
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def format_messages(messages)
|
|
11
|
+
messages.map do |msg|
|
|
12
|
+
{
|
|
13
|
+
role: format_role(msg.role),
|
|
14
|
+
content: Ollama::Media.format_content(msg.content),
|
|
15
|
+
tool_calls: format_tool_calls(msg.tool_calls),
|
|
16
|
+
tool_call_id: msg.tool_call_id
|
|
17
|
+
}.compact
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def format_role(role)
|
|
22
|
+
role.to_s
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
class Ollama
|
|
6
|
+
# Handles formatting of media content (images, audio) for Ollama APIs
|
|
7
|
+
module Media
|
|
8
|
+
extend OpenAI::Media
|
|
9
|
+
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
def format_content(content)
|
|
13
|
+
return content.value if content.is_a?(RubyLLM::Content::Raw)
|
|
14
|
+
return content.to_json if content.is_a?(Hash) || content.is_a?(Array)
|
|
15
|
+
return content unless content.is_a?(Content)
|
|
16
|
+
|
|
17
|
+
parts = []
|
|
18
|
+
parts << format_text(content.text) if content.text
|
|
19
|
+
|
|
20
|
+
content.attachments.each do |attachment|
|
|
21
|
+
case attachment.type
|
|
22
|
+
when :image
|
|
23
|
+
parts << Ollama::Media.format_image(attachment)
|
|
24
|
+
when :text
|
|
25
|
+
parts << format_text_file(attachment)
|
|
26
|
+
else
|
|
27
|
+
raise UnsupportedAttachmentError, attachment.mime_type
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
parts
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def format_image(image)
|
|
35
|
+
{
|
|
36
|
+
type: 'image_url',
|
|
37
|
+
image_url: {
|
|
38
|
+
url: image.for_llm,
|
|
39
|
+
detail: 'auto'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
class Ollama
|
|
6
|
+
# Models methods for the Ollama API integration
|
|
7
|
+
module Models
|
|
8
|
+
def models_url
|
|
9
|
+
'models'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def parse_list_models_response(response, slug, _capabilities)
|
|
13
|
+
data = response.body['data'] || []
|
|
14
|
+
data.map do |model|
|
|
15
|
+
Model::Info.new(
|
|
16
|
+
id: model['id'],
|
|
17
|
+
name: model['id'],
|
|
18
|
+
provider: slug,
|
|
19
|
+
family: 'ollama',
|
|
20
|
+
created_at: model['created'] ? Time.at(model['created']) : nil,
|
|
21
|
+
modalities: {
|
|
22
|
+
input: %w[text image],
|
|
23
|
+
output: %w[text]
|
|
24
|
+
},
|
|
25
|
+
capabilities: %w[streaming function_calling structured_output vision],
|
|
26
|
+
pricing: {},
|
|
27
|
+
metadata: {
|
|
28
|
+
owned_by: model['owned_by']
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
# Ollama API integration.
|
|
6
|
+
class Ollama < OpenAI
|
|
7
|
+
include Ollama::Chat
|
|
8
|
+
include Ollama::Media
|
|
9
|
+
include Ollama::Models
|
|
10
|
+
|
|
11
|
+
def api_base
|
|
12
|
+
@config.ollama_api_base
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def headers
|
|
16
|
+
{}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
def configuration_requirements
|
|
21
|
+
%i[ollama_api_base]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def local?
|
|
25
|
+
true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|