ruby_llm 1.16.0 → 2.0.0.rc2
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/.rdoc_options +25 -0
- data/README.md +85 -32
- data/exe/ruby_llm +8 -0
- data/lib/generators/ruby_llm/agent/templates/agent.rb.tt +0 -1
- data/lib/generators/ruby_llm/chat_ui/chat_ui_generator.rb +3 -43
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/chats_controller.rb.tt +11 -3
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/messages_controller.rb.tt +8 -0
- data/lib/generators/ruby_llm/chat_ui/templates/controllers/models_controller.rb.tt +4 -4
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/chats/_chat.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/chats/_form.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/chats/index.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/chats/show.html.erb.tt +2 -2
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/messages/_assistant.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/messages/_system.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/messages/_tool.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/messages/_tool_calls.html.erb.tt +6 -4
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/messages/_user.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/messages/tool_calls/_default.html.erb.tt +2 -2
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/models/_model.html.erb.tt +5 -6
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/models/index.html.erb.tt +2 -2
- data/lib/generators/ruby_llm/chat_ui/templates/tailwind/views/models/show.html.erb.tt +5 -5
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_chat.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_form.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/index.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/views/chats/show.html.erb.tt +2 -2
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_assistant.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_system.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_tool.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_tool_calls.html.erb.tt +6 -4
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_user.html.erb.tt +1 -1
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt +4 -6
- data/lib/generators/ruby_llm/chat_ui/templates/views/messages/tool_calls/_default.html.erb.tt +2 -2
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/_model.html.erb.tt +5 -6
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/index.html.erb.tt +2 -2
- data/lib/generators/ruby_llm/chat_ui/templates/views/models/show.html.erb.tt +3 -3
- data/lib/generators/ruby_llm/generator_helpers.rb +106 -62
- data/lib/generators/ruby_llm/install/install_generator.rb +3 -11
- data/lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt +2 -0
- data/lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt +14 -8
- data/lib/generators/ruby_llm/install/templates/create_ruby_llm_records_migration.rb.tt +117 -0
- data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +0 -8
- data/lib/generators/ruby_llm/provider/cli.rb +175 -0
- data/lib/generators/ruby_llm/provider/scaffold.rb +323 -0
- data/lib/generators/ruby_llm/provider/templates/core/provider.rb.erb +37 -0
- data/lib/generators/ruby_llm/provider/templates/core/provider_spec.rb.erb +34 -0
- data/lib/generators/ruby_llm/provider/templates/gem/archspec.rb.erb +14 -0
- data/lib/generators/ruby_llm/provider/templates/gem/bin/console.erb +15 -0
- data/lib/generators/ruby_llm/provider/templates/gem/bin/setup.erb +5 -0
- data/lib/generators/ruby_llm/provider/templates/gem/chat_schema_spec.rb.erb +30 -0
- data/lib/generators/ruby_llm/provider/templates/gem/chat_spec.rb.erb +35 -0
- data/lib/generators/ruby_llm/provider/templates/gem/chat_streaming_spec.rb.erb +22 -0
- data/lib/generators/ruby_llm/provider/templates/gem/chat_tools_spec.rb.erb +30 -0
- data/lib/generators/ruby_llm/provider/templates/gem/ci.yml.erb +32 -0
- data/lib/generators/ruby_llm/provider/templates/gem/embedding_spec.rb.erb +49 -0
- data/lib/generators/ruby_llm/provider/templates/gem/env.erb +2 -0
- data/lib/generators/ruby_llm/provider/templates/gem/fixtures_gitkeep.erb +1 -0
- data/lib/generators/ruby_llm/provider/templates/gem/flayignore.erb +1 -0
- data/lib/generators/ruby_llm/provider/templates/gem/gemfile.erb +23 -0
- data/lib/generators/ruby_llm/provider/templates/gem/gemspec.erb +28 -0
- data/lib/generators/ruby_llm/provider/templates/gem/gitignore.erb +7 -0
- data/lib/generators/ruby_llm/provider/templates/gem/gitleaks.yml.erb +22 -0
- data/lib/generators/ruby_llm/provider/templates/gem/image_spec.rb.erb +23 -0
- data/lib/generators/ruby_llm/provider/templates/gem/license.erb +21 -0
- data/lib/generators/ruby_llm/provider/templates/gem/models.rb.erb +19 -0
- data/lib/generators/ruby_llm/provider/templates/gem/models_spec.rb.erb +17 -0
- data/lib/generators/ruby_llm/provider/templates/gem/moderation_spec.rb.erb +22 -0
- data/lib/generators/ruby_llm/provider/templates/gem/overcommit.yml.erb +31 -0
- data/lib/generators/ruby_llm/provider/templates/gem/provider.rb.erb +52 -0
- data/lib/generators/ruby_llm/provider/templates/gem/provider_spec.rb.erb +38 -0
- data/lib/generators/ruby_llm/provider/templates/gem/rakefile.erb +38 -0
- data/lib/generators/ruby_llm/provider/templates/gem/readme.md.erb +50 -0
- data/lib/generators/ruby_llm/provider/templates/gem/release.yml.erb +36 -0
- data/lib/generators/ruby_llm/provider/templates/gem/rerank_spec.rb.erb +23 -0
- data/lib/generators/ruby_llm/provider/templates/gem/rspec.erb +2 -0
- data/lib/generators/ruby_llm/provider/templates/gem/rubocop.yml.erb +29 -0
- data/lib/generators/ruby_llm/provider/templates/gem/rubyllm_configuration.rb.erb +14 -0
- data/lib/generators/ruby_llm/provider/templates/gem/spec_helper.rb.erb +26 -0
- data/lib/generators/ruby_llm/provider/templates/gem/speech_spec.rb.erb +25 -0
- data/lib/generators/ruby_llm/provider/templates/gem/vcr_configuration.rb.erb +16 -0
- data/lib/generators/ruby_llm/provider/templates/gem/video_spec.rb.erb +27 -0
- data/lib/generators/ruby_llm/schema/schema_generator.rb +5 -1
- data/lib/generators/ruby_llm/schema/templates/schema.rb.tt +1 -1
- data/lib/generators/ruby_llm/tool/templates/tailwind/tool_call.html.erb.tt +13 -0
- data/lib/generators/ruby_llm/tool/templates/tailwind/tool_result.html.erb.tt +21 -0
- data/lib/generators/ruby_llm/tool/templates/tool.rb.tt +3 -3
- data/lib/generators/ruby_llm/tool/templates/tool_call.html.erb.tt +7 -12
- data/lib/generators/ruby_llm/tool/templates/tool_result.html.erb.tt +5 -2
- data/lib/generators/ruby_llm/tool/tool_generator.rb +25 -59
- data/lib/generators/ruby_llm/upgrade/templates/backfill_v2_data.rb.tt +461 -0
- data/lib/generators/ruby_llm/upgrade/templates/cleanup_v2_upgrade.rb.tt +101 -0
- data/lib/generators/ruby_llm/upgrade/templates/finish_v2_upgrade.rb.tt +215 -0
- data/lib/generators/ruby_llm/upgrade/templates/prepare_v2_upgrade.rb.tt +660 -0
- data/lib/generators/ruby_llm/upgrade/templates/ruby_llm_upgrade.rb.tt +222 -0
- data/lib/generators/ruby_llm/upgrade/templates/upgrade_initializer.rb.tt +13 -0
- data/lib/generators/ruby_llm/upgrade/upgrade_generator.rb +167 -0
- data/lib/generators/ruby_llm/upgrade/upgrade_migration.rb +344 -0
- data/lib/ruby_llm/accounting/usage.rb +245 -0
- data/lib/ruby_llm/active_record/acts_as.rb +94 -111
- data/lib/ruby_llm/active_record/attachment_helpers.rb +186 -0
- data/lib/ruby_llm/active_record/batch.rb +97 -0
- data/lib/ruby_llm/active_record/chat_methods.rb +828 -305
- data/lib/ruby_llm/active_record/message_methods.rb +113 -136
- data/lib/ruby_llm/active_record/model.rb +135 -0
- data/lib/ruby_llm/active_record/payload_helpers.rb +1 -2
- data/lib/ruby_llm/active_record/tool_call.rb +33 -0
- data/lib/ruby_llm/active_record/usage.rb +61 -0
- data/lib/ruby_llm/agent.rb +1065 -151
- data/lib/ruby_llm/aliases.json +268 -100
- data/lib/ruby_llm/attachment.rb +187 -48
- data/lib/ruby_llm/batch.rb +432 -0
- data/lib/ruby_llm/cached_content.rb +112 -0
- data/lib/ruby_llm/chat/tool_concurrency.rb +111 -0
- data/lib/ruby_llm/chat.rb +1127 -198
- data/lib/ruby_llm/chunk.rb +10 -0
- data/lib/ruby_llm/citation.rb +105 -0
- data/lib/ruby_llm/configuration.rb +261 -24
- data/lib/ruby_llm/context.rb +128 -6
- data/lib/ruby_llm/cost.rb +217 -80
- data/lib/ruby_llm/downloaded_file.rb +33 -0
- data/lib/ruby_llm/embedding.rb +121 -17
- data/lib/ruby_llm/embedding_request.rb +53 -0
- data/lib/ruby_llm/error.rb +159 -23
- data/lib/ruby_llm/fallback.rb +133 -0
- data/lib/ruby_llm/files/mime_type.rb +97 -0
- data/lib/ruby_llm/image.rb +153 -32
- data/lib/ruby_llm/message.rb +233 -54
- data/lib/ruby_llm/model/modalities.rb +17 -4
- data/lib/ruby_llm/model/pricing.rb +24 -5
- data/lib/ruby_llm/model/pricing_category.rb +103 -14
- data/lib/ruby_llm/model/pricing_tier.rb +55 -15
- data/lib/ruby_llm/model.rb +244 -2
- data/lib/ruby_llm/models/aliases.rb +41 -0
- data/lib/ruby_llm/models/registry.rb +165 -0
- data/lib/ruby_llm/models/schema.rb +99 -0
- data/lib/ruby_llm/models.json +73261 -33733
- data/lib/ruby_llm/models.rb +477 -215
- data/lib/ruby_llm/moderation.rb +139 -26
- data/lib/ruby_llm/ocr.rb +112 -0
- data/lib/ruby_llm/prompt.rb +79 -0
- data/lib/ruby_llm/protocol/binary_streaming.rb +65 -0
- data/lib/ruby_llm/protocol/stream_accumulator.rb +214 -0
- data/lib/ruby_llm/protocol/streaming.rb +230 -0
- data/lib/ruby_llm/protocol.rb +662 -0
- data/lib/ruby_llm/protocols/anthropic/batches.rb +73 -0
- data/lib/ruby_llm/protocols/anthropic/chat.rb +548 -0
- data/lib/ruby_llm/protocols/anthropic/embeddings.rb +14 -0
- data/lib/ruby_llm/protocols/anthropic/files.rb +38 -0
- data/lib/ruby_llm/protocols/anthropic/media.rb +141 -0
- data/lib/ruby_llm/protocols/anthropic/models.rb +129 -0
- data/lib/ruby_llm/protocols/anthropic/streaming.rb +167 -0
- data/lib/ruby_llm/{providers → protocols}/anthropic/tools.rb +24 -41
- data/lib/ruby_llm/protocols/anthropic.rb +101 -0
- data/lib/ruby_llm/protocols/azure/files.rb +16 -0
- data/lib/ruby_llm/protocols/bedrock/async_videos.rb +109 -0
- data/lib/ruby_llm/protocols/bedrock/batches.rb +129 -0
- data/lib/ruby_llm/protocols/bedrock/files.rb +110 -0
- data/lib/ruby_llm/protocols/bedrock/guardrails.rb +122 -0
- data/lib/ruby_llm/protocols/bedrock/rerank.rb +95 -0
- data/lib/ruby_llm/protocols/chat_completions/batches.rb +32 -0
- data/lib/ruby_llm/protocols/chat_completions/chat.rb +493 -0
- data/lib/ruby_llm/protocols/chat_completions/embedding_batches.rb +35 -0
- data/lib/ruby_llm/protocols/chat_completions/embeddings.rb +60 -0
- data/lib/ruby_llm/protocols/chat_completions/images.rb +127 -0
- data/lib/ruby_llm/{providers/openai → protocols/chat_completions}/media.rb +30 -17
- data/lib/ruby_llm/protocols/chat_completions/models.rb +39 -0
- data/lib/ruby_llm/protocols/chat_completions/moderation.rb +52 -0
- data/lib/ruby_llm/protocols/chat_completions/rerank.rb +56 -0
- data/lib/ruby_llm/protocols/chat_completions/speech.rb +40 -0
- data/lib/ruby_llm/protocols/chat_completions/streaming.rb +69 -0
- data/lib/ruby_llm/{providers/openai → protocols/chat_completions}/tools.rb +15 -17
- data/lib/ruby_llm/protocols/chat_completions/transcription.rb +150 -0
- data/lib/ruby_llm/protocols/chat_completions.rb +21 -0
- data/lib/ruby_llm/protocols/cohere/batch_requests.rb +75 -0
- data/lib/ruby_llm/protocols/cohere/batches.rb +98 -0
- data/lib/ruby_llm/protocols/cohere/chat.rb +227 -0
- data/lib/ruby_llm/protocols/cohere/datasets.rb +102 -0
- data/lib/ruby_llm/protocols/cohere/embeddings.rb +68 -0
- data/lib/ruby_llm/protocols/cohere/media.rb +77 -0
- data/lib/ruby_llm/protocols/cohere/models.rb +92 -0
- data/lib/ruby_llm/protocols/cohere/ocr.rb +63 -0
- data/lib/ruby_llm/protocols/cohere/rerank.rb +52 -0
- data/lib/ruby_llm/protocols/cohere/streaming.rb +105 -0
- data/lib/ruby_llm/protocols/cohere/tokenization.rb +22 -0
- data/lib/ruby_llm/protocols/cohere/tools.rb +132 -0
- data/lib/ruby_llm/protocols/cohere/transcription.rb +41 -0
- data/lib/ruby_llm/protocols/cohere.rb +21 -0
- data/lib/ruby_llm/protocols/converse/batches.rb +55 -0
- data/lib/ruby_llm/protocols/converse/chat.rb +695 -0
- data/lib/ruby_llm/protocols/converse/media.rb +178 -0
- data/lib/ruby_llm/protocols/converse/streaming.rb +432 -0
- data/lib/ruby_llm/protocols/converse/thinking_stream.rb +56 -0
- data/lib/ruby_llm/protocols/converse.rb +54 -0
- data/lib/ruby_llm/protocols/deepgram/models.rb +74 -0
- data/lib/ruby_llm/protocols/deepgram/speech.rb +93 -0
- data/lib/ruby_llm/protocols/deepgram/streaming_transcription.rb +89 -0
- data/lib/ruby_llm/protocols/deepgram/transcription.rb +96 -0
- data/lib/ruby_llm/protocols/deepgram.rb +19 -0
- data/lib/ruby_llm/protocols/deepseek/files.rb +31 -0
- data/lib/ruby_llm/protocols/elevenlabs/assets.rb +36 -0
- data/lib/ruby_llm/protocols/elevenlabs/flows/images.rb +74 -0
- data/lib/ruby_llm/protocols/elevenlabs/flows/media.rb +42 -0
- data/lib/ruby_llm/protocols/elevenlabs/flows/videos.rb +93 -0
- data/lib/ruby_llm/protocols/elevenlabs/flows.rb +14 -0
- data/lib/ruby_llm/protocols/elevenlabs/models.rb +64 -0
- data/lib/ruby_llm/protocols/elevenlabs/speech.rb +67 -0
- data/lib/ruby_llm/protocols/elevenlabs/streaming_transcription.rb +127 -0
- data/lib/ruby_llm/protocols/elevenlabs/transcription.rb +61 -0
- data/lib/ruby_llm/protocols/elevenlabs.rb +15 -0
- data/lib/ruby_llm/protocols/files.rb +119 -0
- data/lib/ruby_llm/protocols/gemini/batches.rb +162 -0
- data/lib/ruby_llm/protocols/gemini/caches.rb +59 -0
- data/lib/ruby_llm/protocols/gemini/chat.rb +453 -0
- data/lib/ruby_llm/protocols/gemini/embedding_batches.rb +86 -0
- data/lib/ruby_llm/protocols/gemini/embeddings.rb +70 -0
- data/lib/ruby_llm/protocols/gemini/file_transcription.rb +32 -0
- data/lib/ruby_llm/protocols/gemini/files.rb +115 -0
- data/lib/ruby_llm/protocols/gemini/images.rb +183 -0
- data/lib/ruby_llm/protocols/gemini/live_transcription.rb +140 -0
- data/lib/ruby_llm/{providers → protocols}/gemini/media.rb +17 -11
- data/lib/ruby_llm/protocols/gemini/models.rb +71 -0
- data/lib/ruby_llm/protocols/gemini/speech.rb +56 -0
- data/lib/ruby_llm/protocols/gemini/streaming.rb +96 -0
- data/lib/ruby_llm/protocols/gemini/tools.rb +157 -0
- data/lib/ruby_llm/{providers → protocols}/gemini/transcription.rb +22 -22
- data/lib/ruby_llm/protocols/gemini/videos.rb +103 -0
- data/lib/ruby_llm/protocols/gemini.rb +35 -0
- data/lib/ruby_llm/protocols/gpustack/responses.rb +111 -0
- data/lib/ruby_llm/protocols/gpustack/tokenization.rb +22 -0
- data/lib/ruby_llm/protocols/gpustack/videos.rb +96 -0
- data/lib/ruby_llm/protocols/interactions/chat.rb +145 -0
- data/lib/ruby_llm/protocols/interactions/content.rb +90 -0
- data/lib/ruby_llm/protocols/interactions/streaming.rb +91 -0
- data/lib/ruby_llm/protocols/interactions/tools.rb +51 -0
- data/lib/ruby_llm/protocols/interactions/transcription.rb +58 -0
- data/lib/ruby_llm/protocols/interactions.rb +29 -0
- data/lib/ruby_llm/protocols/invoke_model/cohere_embeddings.rb +51 -0
- data/lib/ruby_llm/protocols/invoke_model/embedding_batches.rb +111 -0
- data/lib/ruby_llm/protocols/invoke_model/nova_embeddings.rb +50 -0
- data/lib/ruby_llm/protocols/invoke_model/stability_images.rb +103 -0
- data/lib/ruby_llm/protocols/invoke_model/titan_multimodal_embeddings.rb +33 -0
- data/lib/ruby_llm/protocols/invoke_model/titan_text_embeddings.rb +44 -0
- data/lib/ruby_llm/protocols/invoke_model.rb +57 -0
- data/lib/ruby_llm/protocols/mistral/content.rb +49 -0
- data/lib/ruby_llm/protocols/mistral/conversations/chat.rb +160 -0
- data/lib/ruby_llm/protocols/mistral/conversations/images.rb +43 -0
- data/lib/ruby_llm/protocols/mistral/conversations/streaming.rb +83 -0
- data/lib/ruby_llm/protocols/mistral/conversations.rb +30 -0
- data/lib/ruby_llm/protocols/mistral/files.rb +36 -0
- data/lib/ruby_llm/protocols/mistral/multi_completion.rb +160 -0
- data/lib/ruby_llm/protocols/openai/batches.rb +126 -0
- data/lib/ruby_llm/protocols/openai/files.rb +42 -0
- data/lib/ruby_llm/protocols/openrouter/batches.rb +147 -0
- data/lib/ruby_llm/protocols/openrouter/files.rb +24 -0
- data/lib/ruby_llm/protocols/openrouter/responses.rb +53 -0
- data/lib/ruby_llm/protocols/openrouter/transcription.rb +51 -0
- data/lib/ruby_llm/protocols/perplexity/files.rb +48 -0
- data/lib/ruby_llm/protocols/perplexity/router.rb +59 -0
- data/lib/ruby_llm/protocols/responses/approvals.rb +32 -0
- data/lib/ruby_llm/protocols/responses/batches.rb +32 -0
- data/lib/ruby_llm/protocols/responses/chat.rb +476 -0
- data/lib/ruby_llm/protocols/responses/compaction.rb +29 -0
- data/lib/ruby_llm/protocols/responses/media.rb +61 -0
- data/lib/ruby_llm/protocols/responses/streaming.rb +117 -0
- data/lib/ruby_llm/protocols/responses/token_counting.rb +26 -0
- data/lib/ruby_llm/protocols/responses/tools.rb +39 -0
- data/lib/ruby_llm/protocols/responses.rb +35 -0
- data/lib/ruby_llm/protocols/vertexai/batch_prediction.rb +155 -0
- data/lib/ruby_llm/protocols/vertexai/embedding_prediction/requests.rb +85 -0
- data/lib/ruby_llm/protocols/vertexai/embedding_prediction/results.rb +74 -0
- data/lib/ruby_llm/protocols/vertexai/embedding_prediction.rb +56 -0
- data/lib/ruby_llm/protocols/vertexai/files.rb +101 -0
- data/lib/ruby_llm/protocols/vertexai/ranking.rb +69 -0
- data/lib/ruby_llm/protocols/vertexai/research.rb +193 -0
- data/lib/ruby_llm/protocols/xai/files.rb +30 -0
- data/lib/ruby_llm/protocols/xai/streaming_transcription.rb +120 -0
- data/lib/ruby_llm/protocols/xai/tokenization.rb +23 -0
- data/lib/ruby_llm/provider.rb +560 -128
- data/lib/ruby_llm/providers/anthropic/capabilities.rb +5 -7
- data/lib/ruby_llm/providers/anthropic.rb +4 -6
- data/lib/ruby_llm/providers/azure/audio.rb +18 -0
- data/lib/ruby_llm/providers/azure/capabilities.rb +16 -0
- data/lib/ruby_llm/providers/azure/chat.rb +2 -9
- data/lib/ruby_llm/providers/azure/chat_completions/batches.rb +29 -0
- data/lib/ruby_llm/providers/azure/chat_completions.rb +80 -0
- data/lib/ruby_llm/providers/azure/cohere.rb +33 -0
- data/lib/ruby_llm/providers/azure/embeddings.rb +3 -2
- data/lib/ruby_llm/providers/azure/images.rb +22 -0
- data/lib/ruby_llm/providers/azure/media.rb +5 -14
- data/lib/ruby_llm/providers/azure/models.rb +35 -0
- data/lib/ruby_llm/providers/azure/responses.rb +26 -0
- data/lib/ruby_llm/providers/azure/videos.rb +64 -0
- data/lib/ruby_llm/providers/azure.rb +77 -78
- data/lib/ruby_llm/providers/bedrock/auth.rb +60 -41
- data/lib/ruby_llm/providers/bedrock/capabilities.rb +18 -0
- data/lib/ruby_llm/providers/bedrock/mantle/anthropic.rb +39 -0
- data/lib/ruby_llm/providers/bedrock/mantle/chat_completions.rb +23 -0
- data/lib/ruby_llm/providers/bedrock/mantle/responses.rb +24 -0
- data/lib/ruby_llm/providers/bedrock/mantle/voxtral.rb +96 -0
- data/lib/ruby_llm/providers/bedrock/mantle.rb +57 -0
- data/lib/ruby_llm/providers/bedrock/models.rb +193 -41
- data/lib/ruby_llm/providers/bedrock.rb +216 -45
- data/lib/ruby_llm/providers/cohere.rb +31 -0
- data/lib/ruby_llm/providers/deepgram.rb +37 -0
- data/lib/ruby_llm/providers/deepseek/capabilities.rb +4 -51
- data/lib/ruby_llm/providers/deepseek/chat.rb +49 -2
- data/lib/ruby_llm/providers/deepseek/responses.rb +68 -0
- data/lib/ruby_llm/providers/deepseek.rb +9 -2
- data/lib/ruby_llm/providers/elevenlabs.rb +35 -0
- data/lib/ruby_llm/providers/gemini/capabilities.rb +8 -107
- data/lib/ruby_llm/providers/gemini.rb +15 -8
- data/lib/ruby_llm/providers/gpustack/chat.rb +2 -16
- data/lib/ruby_llm/providers/gpustack/embeddings.rb +28 -0
- data/lib/ruby_llm/providers/gpustack/media.rb +17 -16
- data/lib/ruby_llm/providers/gpustack/models.rb +72 -62
- data/lib/ruby_llm/providers/gpustack/speech.rb +15 -0
- data/lib/ruby_llm/providers/gpustack/transcription.rb +29 -0
- data/lib/ruby_llm/providers/gpustack.rb +35 -11
- data/lib/ruby_llm/providers/mistral/capabilities.rb +7 -155
- data/lib/ruby_llm/providers/mistral/chat.rb +37 -61
- data/lib/ruby_llm/providers/mistral/chat_completions/batches.rb +120 -0
- data/lib/ruby_llm/providers/mistral/chat_completions.rb +21 -0
- data/lib/ruby_llm/providers/mistral/conversations.rb +12 -0
- data/lib/ruby_llm/providers/mistral/embeddings.rb +6 -4
- data/lib/ruby_llm/providers/mistral/media.rb +6 -18
- data/lib/ruby_llm/providers/mistral/models.rb +57 -23
- data/lib/ruby_llm/providers/mistral/ocr.rb +47 -0
- data/lib/ruby_llm/providers/mistral/speech.rb +51 -0
- data/lib/ruby_llm/providers/mistral/transcription.rb +62 -0
- data/lib/ruby_llm/providers/mistral.rb +16 -4
- data/lib/ruby_llm/providers/ollama/chat.rb +7 -13
- data/lib/ruby_llm/providers/ollama/media.rb +6 -15
- data/lib/ruby_llm/providers/ollama/models.rb +50 -9
- data/lib/ruby_llm/providers/ollama.rb +9 -8
- data/lib/ruby_llm/providers/ollama_cloud/models.rb +14 -0
- data/lib/ruby_llm/providers/ollama_cloud.rb +40 -0
- data/lib/ruby_llm/providers/openai/capabilities.rb +54 -259
- data/lib/ruby_llm/providers/openai/models.rb +23 -23
- data/lib/ruby_llm/providers/openai/responses.rb +13 -0
- data/lib/ruby_llm/providers/openai.rb +92 -11
- data/lib/ruby_llm/providers/openrouter/chat.rb +130 -108
- data/lib/ruby_llm/providers/openrouter/embeddings.rb +51 -0
- data/lib/ruby_llm/providers/openrouter/images.rb +44 -43
- data/lib/ruby_llm/providers/openrouter/media.rb +34 -0
- data/lib/ruby_llm/providers/openrouter/models.rb +50 -11
- data/lib/ruby_llm/providers/openrouter/speech.rb +32 -0
- data/lib/ruby_llm/providers/openrouter/streaming.rb +31 -38
- data/lib/ruby_llm/providers/openrouter/videos.rb +81 -0
- data/lib/ruby_llm/providers/openrouter.rb +78 -20
- data/lib/ruby_llm/providers/perplexity/chat.rb +2 -9
- data/lib/ruby_llm/providers/perplexity/embeddings.rb +32 -0
- data/lib/ruby_llm/providers/perplexity/media.rb +5 -21
- data/lib/ruby_llm/providers/perplexity/models.rb +80 -13
- data/lib/ruby_llm/providers/perplexity.rb +28 -20
- data/lib/ruby_llm/providers/vertexai/anthropic/batches.rb +52 -0
- data/lib/ruby_llm/providers/vertexai/anthropic.rb +34 -0
- data/lib/ruby_llm/providers/vertexai/capabilities.rb +19 -0
- data/lib/ruby_llm/providers/vertexai/chat_completions/batches.rb +54 -0
- data/lib/ruby_llm/providers/vertexai/chat_completions.rb +15 -0
- data/lib/ruby_llm/providers/vertexai/embed_content.rb +42 -0
- data/lib/ruby_llm/providers/vertexai/embeddings.rb +22 -7
- data/lib/ruby_llm/providers/vertexai/gemini/batches.rb +42 -0
- data/lib/ruby_llm/providers/vertexai/gemini.rb +69 -0
- data/lib/ruby_llm/providers/vertexai/live_transcription.rb +24 -0
- data/lib/ruby_llm/providers/vertexai/mistral.rb +28 -0
- data/lib/ruby_llm/providers/vertexai/models.rb +145 -43
- data/lib/ruby_llm/providers/vertexai/transcription.rb +49 -4
- data/lib/ruby_llm/providers/vertexai/videos.rb +61 -0
- data/lib/ruby_llm/providers/vertexai.rb +160 -17
- data/lib/ruby_llm/providers/xai/capabilities.rb +18 -0
- data/lib/ruby_llm/providers/xai/chat.rb +3 -2
- data/lib/ruby_llm/providers/xai/chat_completions/batches.rb +108 -0
- data/lib/ruby_llm/providers/xai/chat_completions.rb +19 -0
- data/lib/ruby_llm/providers/xai/images.rb +91 -0
- data/lib/ruby_llm/providers/xai/models.rb +32 -36
- data/lib/ruby_llm/providers/xai/reported_cost.rb +18 -0
- data/lib/ruby_llm/providers/xai/responses.rb +52 -0
- data/lib/ruby_llm/providers/xai/speech.rb +45 -0
- data/lib/ruby_llm/providers/xai/transcription.rb +48 -0
- data/lib/ruby_llm/providers/xai/videos.rb +87 -0
- data/lib/ruby_llm/providers/xai.rb +15 -5
- data/lib/ruby_llm/railtie.rb +7 -16
- data/lib/ruby_llm/rerank.rb +105 -0
- data/lib/ruby_llm/research_job.rb +241 -0
- data/lib/ruby_llm/search_results.rb +68 -0
- data/lib/ruby_llm/server_tool_call.rb +73 -0
- data/lib/ruby_llm/speech.rb +159 -0
- data/lib/ruby_llm/speech_chunk.rb +33 -0
- data/lib/ruby_llm/support/deprecator.rb +22 -0
- data/lib/ruby_llm/support/inspectable.rb +49 -0
- data/lib/ruby_llm/support/instrumentation.rb +41 -0
- data/lib/ruby_llm/support/utils.rb +147 -0
- data/lib/ruby_llm/thinking.rb +127 -20
- data/lib/ruby_llm/tokenization.rb +59 -0
- data/lib/ruby_llm/tokens.rb +103 -33
- data/lib/ruby_llm/tool.rb +266 -91
- data/lib/ruby_llm/tool_call.rb +36 -3
- data/lib/ruby_llm/tools/server_tools.rb +109 -0
- data/lib/ruby_llm/transcription/wav_audio.rb +62 -0
- data/lib/ruby_llm/transcription.rb +138 -13
- data/lib/ruby_llm/transcription_chunk.rb +68 -0
- data/lib/ruby_llm/transport/connection.rb +193 -0
- data/lib/ruby_llm/transport/error_middleware.rb +131 -0
- data/lib/ruby_llm/transport/usage_middleware.rb +28 -0
- data/lib/ruby_llm/transport/websocket_connection.rb +220 -0
- data/lib/ruby_llm/uploaded_file.rb +144 -0
- data/lib/ruby_llm/version.rb +2 -1
- data/lib/ruby_llm/video.rb +136 -0
- data/lib/ruby_llm/video_job.rb +150 -0
- data/lib/ruby_llm/workflow.rb +91 -0
- data/lib/ruby_llm.rb +380 -6
- data/lib/tasks/ruby_llm.rake +21 -16
- data/skills/rubyllm/SKILL.md +81 -0
- data/skills/rubyllm/agents/openai.yaml +4 -0
- metadata +339 -97
- data/lib/generators/ruby_llm/install/templates/add_references_to_chats_tool_calls_and_messages_migration.rb.tt +0 -9
- data/lib/generators/ruby_llm/install/templates/create_models_migration.rb.tt +0 -39
- data/lib/generators/ruby_llm/install/templates/create_tool_calls_migration.rb.tt +0 -21
- data/lib/generators/ruby_llm/install/templates/model_model.rb.tt +0 -3
- data/lib/generators/ruby_llm/install/templates/tool_call_model.rb.tt +0 -3
- data/lib/generators/ruby_llm/upgrade_to_v1_10/templates/add_v1_10_message_columns.rb.tt +0 -19
- data/lib/generators/ruby_llm/upgrade_to_v1_10/upgrade_to_v1_10_generator.rb +0 -50
- data/lib/generators/ruby_llm/upgrade_to_v1_14/templates/add_v1_14_tool_call_columns.rb.tt +0 -7
- data/lib/generators/ruby_llm/upgrade_to_v1_14/upgrade_to_v1_14_generator.rb +0 -49
- data/lib/generators/ruby_llm/upgrade_to_v1_7/templates/migration.rb.tt +0 -145
- data/lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +0 -122
- data/lib/generators/ruby_llm/upgrade_to_v1_9/templates/add_v1_9_message_columns.rb.tt +0 -15
- data/lib/generators/ruby_llm/upgrade_to_v1_9/upgrade_to_v1_9_generator.rb +0 -49
- data/lib/ruby_llm/active_record/acts_as_legacy.rb +0 -597
- data/lib/ruby_llm/active_record/model_methods.rb +0 -82
- data/lib/ruby_llm/active_record/tool_call_methods.rb +0 -18
- data/lib/ruby_llm/aliases.rb +0 -41
- data/lib/ruby_llm/connection.rb +0 -159
- data/lib/ruby_llm/content.rb +0 -91
- data/lib/ruby_llm/deprecator.rb +0 -24
- data/lib/ruby_llm/error_middleware.rb +0 -81
- data/lib/ruby_llm/instrumentation.rb +0 -36
- data/lib/ruby_llm/mime_type.rb +0 -96
- data/lib/ruby_llm/model/info.rb +0 -164
- data/lib/ruby_llm/model_registry.rb +0 -39
- data/lib/ruby_llm/models_schema.json +0 -171
- data/lib/ruby_llm/providers/anthropic/chat.rb +0 -291
- data/lib/ruby_llm/providers/anthropic/content.rb +0 -44
- data/lib/ruby_llm/providers/anthropic/embeddings.rb +0 -20
- data/lib/ruby_llm/providers/anthropic/media.rb +0 -92
- data/lib/ruby_llm/providers/anthropic/models.rb +0 -59
- data/lib/ruby_llm/providers/anthropic/streaming.rb +0 -71
- data/lib/ruby_llm/providers/bedrock/chat.rb +0 -405
- data/lib/ruby_llm/providers/bedrock/media.rb +0 -108
- data/lib/ruby_llm/providers/bedrock/streaming.rb +0 -328
- data/lib/ruby_llm/providers/gemini/chat.rb +0 -542
- data/lib/ruby_llm/providers/gemini/embeddings.rb +0 -37
- data/lib/ruby_llm/providers/gemini/images.rb +0 -47
- data/lib/ruby_llm/providers/gemini/models.rb +0 -38
- data/lib/ruby_llm/providers/gemini/streaming.rb +0 -98
- data/lib/ruby_llm/providers/gemini/tools.rb +0 -234
- data/lib/ruby_llm/providers/gpustack/capabilities.rb +0 -20
- data/lib/ruby_llm/providers/ollama/capabilities.rb +0 -20
- data/lib/ruby_llm/providers/openai/chat.rb +0 -236
- data/lib/ruby_llm/providers/openai/embeddings.rb +0 -33
- data/lib/ruby_llm/providers/openai/images.rb +0 -90
- data/lib/ruby_llm/providers/openai/moderation.rb +0 -34
- data/lib/ruby_llm/providers/openai/streaming.rb +0 -55
- data/lib/ruby_llm/providers/openai/temperature.rb +0 -28
- data/lib/ruby_llm/providers/openai/transcription.rb +0 -71
- data/lib/ruby_llm/providers/perplexity/capabilities.rb +0 -72
- data/lib/ruby_llm/providers/vertexai/chat.rb +0 -14
- data/lib/ruby_llm/providers/vertexai/streaming.rb +0 -14
- data/lib/ruby_llm/stream_accumulator.rb +0 -218
- data/lib/ruby_llm/streaming.rb +0 -179
- data/lib/ruby_llm/tool_concurrency.rb +0 -105
- data/lib/ruby_llm/utils.rb +0 -130
- data/lib/tasks/models.rake +0 -593
- data/lib/tasks/release.rake +0 -94
- data/lib/tasks/vcr.rake +0 -124
|
@@ -7,7 +7,10 @@ module RubyLLM
|
|
|
7
7
|
module Models
|
|
8
8
|
module_function
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
JP_REGIONS = %w[ap-northeast-1 ap-northeast-3].freeze
|
|
11
|
+
AU_REGIONS = %w[ap-southeast-2 ap-southeast-4].freeze
|
|
12
|
+
|
|
13
|
+
MANTLE_ENDPOINT = 'mantle'
|
|
11
14
|
|
|
12
15
|
def models_api_base
|
|
13
16
|
@config.bedrock_api_base || "https://bedrock.#{bedrock_region}.amazonaws.com"
|
|
@@ -17,24 +20,104 @@ module RubyLLM
|
|
|
17
20
|
'/foundation-models'
|
|
18
21
|
end
|
|
19
22
|
|
|
20
|
-
def
|
|
23
|
+
def mantle_models_url
|
|
24
|
+
'v1/models'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def models_dev_alias(model_id, models_dev_by_key, _provider_model = nil)
|
|
28
|
+
normalized_id = model_id.sub(/^[a-z]{2}\./, '')
|
|
29
|
+
context_override = nil
|
|
30
|
+
normalized_id = normalized_id.gsub(/:(\d+)k\b/) do
|
|
31
|
+
context_override = Regexp.last_match(1).to_i * 1000
|
|
32
|
+
''
|
|
33
|
+
end
|
|
34
|
+
source = models_dev_by_key["bedrock:#{normalized_id}"]
|
|
35
|
+
return unless source
|
|
36
|
+
|
|
37
|
+
data = source.to_h.merge(id: model_id)
|
|
38
|
+
data[:context_window] = context_override if context_override
|
|
39
|
+
Model.new(data)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# The mantle catalog reports ids and nothing else, so entries carry
|
|
43
|
+
# only what the endpoint states. models.dev fills in limits and
|
|
44
|
+
# pricing for the ids it knows during a registry refresh.
|
|
45
|
+
def parse_mantle_models_response(response, slug)
|
|
46
|
+
Array(response.body['data']).map do |model_data|
|
|
47
|
+
Model.new(
|
|
48
|
+
id: model_data['id'],
|
|
49
|
+
name: model_data['id'],
|
|
50
|
+
provider: slug,
|
|
51
|
+
created_at: mantle_created_at(model_data['created']),
|
|
52
|
+
modalities: { input: ['text'], output: ['text'] },
|
|
53
|
+
capabilities: ['streaming'],
|
|
54
|
+
metadata: { endpoint: MANTLE_ENDPOINT }
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Models both catalogs list keep their Converse metadata and gain the
|
|
60
|
+
# mantle tag, because mantle is where RubyLLM sends them.
|
|
61
|
+
def merge_mantle_models(converse_models, mantle_models)
|
|
62
|
+
by_id = converse_models.to_h { |model| [model.id, model] }
|
|
63
|
+
|
|
64
|
+
tagged = mantle_models.map do |model|
|
|
65
|
+
listed = by_id.delete(model.id)
|
|
66
|
+
listed ? tag_mantle_endpoint(listed) : model
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
by_id.values + tagged
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def tag_mantle_endpoint(model)
|
|
73
|
+
data = model.to_h
|
|
74
|
+
Model.new(data.merge(metadata: data[:metadata].merge(endpoint: MANTLE_ENDPOINT)))
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def mantle_created_at(created)
|
|
78
|
+
Time.at(created).utc if created.is_a?(Numeric)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def parse_list_models_response(response, slug, profile_ids: [])
|
|
21
82
|
Array(response.body['modelSummaries']).map do |model_data|
|
|
22
|
-
create_model_info(model_data, slug)
|
|
83
|
+
create_model_info(model_data, slug, profile_ids:)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# The region's actual cross-region inference profile ids. Some
|
|
88
|
+
# geography prefixes cannot be synthesized from the region alone:
|
|
89
|
+
# Tokyo serves both apac. and jp. profiles.
|
|
90
|
+
def inference_profile_ids
|
|
91
|
+
ids = []
|
|
92
|
+
token = nil
|
|
93
|
+
|
|
94
|
+
loop do
|
|
95
|
+
url = +'/inference-profiles?maxResults=1000&typeEquals=SYSTEM_DEFINED'
|
|
96
|
+
url << "&nextToken=#{URI.encode_www_form_component(token)}" if token
|
|
97
|
+
body = signed_get(models_api_base, url).body
|
|
98
|
+
ids.concat(Array(body['inferenceProfileSummaries']).map { |summary| summary['inferenceProfileId'] })
|
|
99
|
+
token = body['nextToken']
|
|
100
|
+
break unless token
|
|
23
101
|
end
|
|
102
|
+
|
|
103
|
+
ids.compact
|
|
104
|
+
rescue StandardError => e
|
|
105
|
+
RubyLLM.logger.debug { "Error fetching Bedrock inference profiles: #{e.message}" }
|
|
106
|
+
[]
|
|
24
107
|
end
|
|
25
108
|
|
|
26
|
-
def create_model_info(model_data, slug, _capabilities = nil)
|
|
27
|
-
model_id = model_id_with_region(model_data['modelId'], model_data)
|
|
109
|
+
def create_model_info(model_data, slug, _capabilities = nil, profile_ids: [])
|
|
110
|
+
model_id = model_id_with_region(model_data['modelId'], model_data, profile_ids)
|
|
28
111
|
converse_data = model_data['converse'] || {}
|
|
29
112
|
|
|
30
|
-
Model
|
|
113
|
+
Model.new(
|
|
31
114
|
id: model_id,
|
|
32
115
|
name: model_data['modelName'],
|
|
33
116
|
provider: slug,
|
|
34
117
|
family: model_data['modelFamily'] || model_data['providerName']&.downcase,
|
|
35
118
|
created_at: nil,
|
|
36
119
|
context_window: parse_context_window(model_data),
|
|
37
|
-
max_output_tokens: converse_data['
|
|
120
|
+
max_output_tokens: converse_data['maxTokensMaximum'] || converse_data['maxTokensDefault'],
|
|
38
121
|
modalities: {
|
|
39
122
|
input: normalize_modalities(model_data['inputModalities']),
|
|
40
123
|
output: normalize_modalities(model_data['outputModalities'])
|
|
@@ -50,36 +133,123 @@ module RubyLLM
|
|
|
50
133
|
)
|
|
51
134
|
end
|
|
52
135
|
|
|
53
|
-
def model_id_with_region(model_id, model_data)
|
|
136
|
+
def model_id_with_region(model_id, model_data, profile_ids = [])
|
|
54
137
|
inference_types = Array(model_data['inferenceTypesSupported'])
|
|
55
|
-
|
|
138
|
+
return model_id unless inference_profile_only?(inference_types)
|
|
139
|
+
|
|
140
|
+
listed_profile_id(model_id, profile_ids) || with_region_prefix(model_id, @config.bedrock_region)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def listed_profile_id(model_id, profile_ids)
|
|
144
|
+
candidates = profile_ids.select { |profile_id| profile_id.end_with?(".#{model_id}") }
|
|
145
|
+
preferred = region_prefix_candidates(@config.bedrock_region).filter_map do |prefix|
|
|
146
|
+
candidates.find { |profile_id| profile_id == "#{prefix}.#{model_id}" }
|
|
147
|
+
end.first
|
|
148
|
+
|
|
149
|
+
preferred || candidates.first
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Which endpoint serves a model is a fact about the catalogs, not
|
|
153
|
+
# about the id: mantle spells some Converse models differently and
|
|
154
|
+
# lists models Converse has never heard of. The registry records it,
|
|
155
|
+
# so ask the registry first and read the id only for models it does
|
|
156
|
+
# not list.
|
|
157
|
+
#
|
|
158
|
+
# Claude is the exception. Converse only ever serves it under a dated
|
|
159
|
+
# and versioned id, so a bare anthropic. id means mantle even on
|
|
160
|
+
# accounts whose catalog listing hides Claude behind the AWS Sales
|
|
161
|
+
# agreement.
|
|
162
|
+
def mantle_model?(model_id, models)
|
|
163
|
+
return mantle_model_id?(model_id) if model_id.start_with?('anthropic.')
|
|
164
|
+
|
|
165
|
+
listed = registered_model(model_id, models)
|
|
166
|
+
return listed.metadata[:endpoint].to_s == MANTLE_ENDPOINT if listed
|
|
167
|
+
|
|
168
|
+
mantle_model_id?(model_id)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def registered_model(model_id, models)
|
|
172
|
+
models.all_including_unlisted.find { |model| model.provider == 'bedrock' && model.id == model_id }
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# The bedrock-mantle endpoint serves bare vendor.model ids under
|
|
176
|
+
# exactly that id. Converse ids carry a date or :N version suffix, a
|
|
177
|
+
# cross-region inference prefix, or both.
|
|
178
|
+
def mantle_model_id?(model_id)
|
|
179
|
+
return false if model_id.include?(':') || model_id.match?(/\d{8}/)
|
|
180
|
+
return false if region_prefixed?(model_id)
|
|
181
|
+
|
|
182
|
+
model_id.include?('.')
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def resolve_registry_id(model_id, models, config)
|
|
186
|
+
region = config.bedrock_region.to_s
|
|
187
|
+
return model_id if region.empty?
|
|
188
|
+
return model_id if mantle_model_id?(model_id)
|
|
189
|
+
|
|
190
|
+
candidate = registered_profile_candidate(model_id, models, region)
|
|
191
|
+
return model_id unless candidate
|
|
192
|
+
|
|
193
|
+
inference_types = Array(candidate.metadata[:inference_types] || candidate.metadata['inference_types'])
|
|
194
|
+
inference_profile_only?(inference_types) ? candidate.id : model_id
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def registered_profile_candidate(model_id, models, region)
|
|
198
|
+
region_prefix_candidates(region).each do |prefix|
|
|
199
|
+
prefixed = prefixed_with(model_id, prefix)
|
|
200
|
+
next if prefixed == model_id
|
|
201
|
+
|
|
202
|
+
candidate = models.all_including_unlisted.find { |m| m.provider == 'bedrock' && m.id == prefixed }
|
|
203
|
+
return candidate if candidate
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
nil
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def inference_profile_only?(inference_types)
|
|
210
|
+
inference_types.include?('INFERENCE_PROFILE') && !inference_types.include?('ON_DEMAND')
|
|
56
211
|
end
|
|
57
212
|
|
|
58
213
|
def normalize_inference_profile_id(model_id, inference_types, region)
|
|
59
|
-
return model_id unless
|
|
60
|
-
return model_id if inference_types.include?('ON_DEMAND')
|
|
214
|
+
return model_id unless inference_profile_only?(inference_types)
|
|
61
215
|
|
|
62
216
|
with_region_prefix(model_id, region)
|
|
63
217
|
end
|
|
64
218
|
|
|
65
219
|
def with_region_prefix(model_id, region)
|
|
66
|
-
|
|
220
|
+
prefixed_with(model_id, region_prefix(region))
|
|
221
|
+
end
|
|
67
222
|
|
|
223
|
+
def prefixed_with(model_id, prefix)
|
|
68
224
|
if region_prefixed?(model_id)
|
|
69
|
-
model_id.sub(/\A(?:#{REGION_PREFIXES.join('|')})\./, "#{prefix}.")
|
|
225
|
+
model_id.sub(/\A(?:#{Protocols::Converse::REGION_PREFIXES.join('|')})\./, "#{prefix}.")
|
|
70
226
|
else
|
|
71
227
|
"#{prefix}.#{model_id}"
|
|
72
228
|
end
|
|
73
229
|
end
|
|
74
230
|
|
|
231
|
+
# Inference profile ids use geography prefixes, not region name
|
|
232
|
+
# segments: ap-* regions are apac., GovCloud is us-gov.
|
|
75
233
|
def region_prefix(region)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
234
|
+
region = region.to_s
|
|
235
|
+
return 'us' if region.empty?
|
|
236
|
+
return 'us-gov' if region.start_with?('us-gov')
|
|
237
|
+
|
|
238
|
+
geography = region.split('-').first
|
|
239
|
+
geography == 'ap' ? 'apac' : geography
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Countries with their own residency-preserving profiles come before
|
|
243
|
+
# the broad geography, so Tokyo prefers jp. over apac. Some models
|
|
244
|
+
# ship with only a global. profile, so that is the last resort.
|
|
245
|
+
def region_prefix_candidates(region)
|
|
246
|
+
region = region.to_s
|
|
247
|
+
specific = ('jp' if JP_REGIONS.include?(region)) || ('au' if AU_REGIONS.include?(region))
|
|
248
|
+
[specific, region_prefix(region), 'global'].compact
|
|
79
249
|
end
|
|
80
250
|
|
|
81
251
|
def region_prefixed?(model_id)
|
|
82
|
-
model_id.match?(/\A(?:#{REGION_PREFIXES.join('|')})\./)
|
|
252
|
+
model_id.match?(/\A(?:#{Protocols::Converse::REGION_PREFIXES.join('|')})\./)
|
|
83
253
|
end
|
|
84
254
|
|
|
85
255
|
def normalize_modalities(modalities)
|
|
@@ -93,40 +263,22 @@ module RubyLLM
|
|
|
93
263
|
end
|
|
94
264
|
end
|
|
95
265
|
|
|
266
|
+
# A summary's converse block is metadata Bedrock fills in for some
|
|
267
|
+
# models, not a statement that Converse serves them: Nova Lite,
|
|
268
|
+
# Llama 3.3 and Mistral Large take tool calls without one. Whether
|
|
269
|
+
# Converse accepts the model at all is the closest thing the listing
|
|
270
|
+
# has to a tool-use flag.
|
|
96
271
|
def parse_capabilities(model_data)
|
|
97
272
|
capabilities = []
|
|
98
273
|
capabilities << 'streaming' if model_data['responseStreamingSupported']
|
|
99
274
|
|
|
100
275
|
converse = model_data['converse'] || {}
|
|
101
|
-
capabilities << 'function_calling' if
|
|
276
|
+
capabilities << 'function_calling' if model_data.dig('inferenceAPIsSupported', 'converse', 'sync')
|
|
102
277
|
capabilities << 'reasoning' if converse.dig('reasoningSupported', 'embedded')
|
|
103
|
-
capabilities << 'structured_output' if supports_structured_output?(model_data['modelId'])
|
|
104
278
|
|
|
105
279
|
capabilities
|
|
106
280
|
end
|
|
107
281
|
|
|
108
|
-
# Structured output supported on Claude 4.5+ and assumed for future major versions.
|
|
109
|
-
# Bedrock IDs look like: us.anthropic.claude-haiku-4-5-20251001-v1:0
|
|
110
|
-
# Must handle optional region prefix (us./eu./global.) and anthropic. prefix.
|
|
111
|
-
def supports_structured_output?(model_id)
|
|
112
|
-
return false unless model_id
|
|
113
|
-
|
|
114
|
-
normalized = model_id.sub(/\A(?:#{REGION_PREFIXES.join('|')})\./, '').delete_prefix('anthropic.')
|
|
115
|
-
match = normalized.match(/claude-(?:opus|sonnet|haiku)-(\d+)-(\d{1,2})(?:\b|-)/)
|
|
116
|
-
return false unless match
|
|
117
|
-
|
|
118
|
-
major = match[1].to_i
|
|
119
|
-
minor = match[2].to_i
|
|
120
|
-
major > 4 || (major == 4 && minor >= 5)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def reasoning_embedded?(model)
|
|
124
|
-
metadata = RubyLLM::Utils.deep_symbolize_keys(model.metadata || {})
|
|
125
|
-
converse = metadata[:converse] || {}
|
|
126
|
-
reasoning_supported = converse[:reasoningSupported] || {}
|
|
127
|
-
reasoning_supported[:embedded] || false
|
|
128
|
-
end
|
|
129
|
-
|
|
130
282
|
def parse_context_window(model_data)
|
|
131
283
|
value = model_data.dig('description', 'maxContextWindow')
|
|
132
284
|
return unless value.is_a?(String)
|
|
@@ -2,97 +2,268 @@
|
|
|
2
2
|
|
|
3
3
|
module RubyLLM
|
|
4
4
|
module Providers
|
|
5
|
-
# AWS Bedrock
|
|
5
|
+
# AWS Bedrock integration.
|
|
6
6
|
class Bedrock < Provider
|
|
7
7
|
include Bedrock::Auth
|
|
8
|
-
include Bedrock::Chat
|
|
9
|
-
include Bedrock::Media
|
|
10
8
|
include Bedrock::Models
|
|
11
|
-
|
|
9
|
+
|
|
10
|
+
protocol :converse, Protocols::Converse, batches: Protocols::Converse::Batches
|
|
11
|
+
protocol :mantle_anthropic, Bedrock::Mantle::Anthropic
|
|
12
|
+
protocol :mantle_responses, Bedrock::Mantle::Responses
|
|
13
|
+
protocol :mantle_chat_completions, Bedrock::Mantle::ChatCompletions
|
|
14
|
+
protocol :voxtral_transcription, Bedrock::Mantle::Voxtral
|
|
15
|
+
protocol :titan_text_embeddings, Protocols::InvokeModel::TitanTextEmbeddings,
|
|
16
|
+
batches: Protocols::InvokeModel::EmbeddingBatches
|
|
17
|
+
protocol :titan_multimodal_embeddings, Protocols::InvokeModel::TitanMultimodalEmbeddings,
|
|
18
|
+
batches: Protocols::InvokeModel::EmbeddingBatches
|
|
19
|
+
protocol :cohere_embeddings, Protocols::InvokeModel::CohereEmbeddings
|
|
20
|
+
protocol :nova_embeddings, Protocols::InvokeModel::NovaEmbeddings
|
|
21
|
+
protocol :stability_images, Protocols::InvokeModel::StabilityImages
|
|
22
|
+
protocol :rerank, Protocols::Bedrock::Rerank
|
|
23
|
+
protocol :guardrails, Protocols::Bedrock::Guardrails
|
|
24
|
+
protocol :async_videos, Protocols::Bedrock::AsyncVideos
|
|
25
|
+
protocol :files, Protocols::Bedrock::Files
|
|
26
|
+
|
|
27
|
+
def self.capabilities
|
|
28
|
+
Bedrock::Capabilities
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.resolve_registry_id(model_id, models, config = RubyLLM.config)
|
|
32
|
+
Models.resolve_registry_id(model_id, models, config)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.models_dev_alias(...)
|
|
36
|
+
Models.models_dev_alias(...)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def protocol_for(model, operation: nil, **)
|
|
40
|
+
return protocols[:guardrails] if operation == :moderate
|
|
41
|
+
|
|
42
|
+
model_id = model_id_for(model)
|
|
43
|
+
return embedding_protocol_for(model_id) if operation == :embed
|
|
44
|
+
return image_protocol_for(model_id) if operation == :paint
|
|
45
|
+
return protocols[:rerank] if operation == :rerank
|
|
46
|
+
return video_protocol_for(model_id) if operation == :animate
|
|
47
|
+
return protocols[:voxtral_transcription] if voxtral_transcription?(operation, model_id)
|
|
48
|
+
return mantle_protocol_for(model_id) if mantle_model?(model_id)
|
|
49
|
+
|
|
50
|
+
super
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Un-versioned ids such as anthropic.claude-sonnet-5 and
|
|
54
|
+
# openai.gpt-oss-20b are served by the bedrock-mantle endpoint rather
|
|
55
|
+
# than by Converse.
|
|
56
|
+
def mantle_model?(model_id)
|
|
57
|
+
Models.mantle_model?(model_id, RubyLLM.models)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def mantle_api_base
|
|
61
|
+
@config.bedrock_mantle_api_base || "https://bedrock-mantle.#{bedrock_region}.api.aws"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def mantle_connection
|
|
65
|
+
@mantle_connection ||= Transport::Connection.new(self, @config, api_base: mantle_api_base)
|
|
66
|
+
end
|
|
12
67
|
|
|
13
68
|
def api_base
|
|
14
69
|
@config.bedrock_api_base || "https://bedrock-runtime.#{bedrock_region}.amazonaws.com"
|
|
15
70
|
end
|
|
16
71
|
|
|
72
|
+
def control_api_base
|
|
73
|
+
@config.bedrock_api_base || "https://bedrock.#{bedrock_region}.amazonaws.com"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def agent_api_base # :nodoc:
|
|
77
|
+
@config.bedrock_api_base || "https://bedrock-agent-runtime.#{bedrock_region}.amazonaws.com"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def agent_connection # :nodoc:
|
|
81
|
+
@agent_connection ||= Transport::Connection.new(self, @config, api_base: agent_api_base)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def rerank_model_arn(model_id) # :nodoc:
|
|
85
|
+
return model_id if model_id.start_with?('arn:')
|
|
86
|
+
|
|
87
|
+
unless %w[amazon.rerank-v1:0 cohere.rerank-v3-5:0].include?(model_id)
|
|
88
|
+
raise Error, "Bedrock reranking is not supported for #{model_id.inspect}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
"arn:aws:bedrock:#{bedrock_region}::foundation-model/#{model_id}"
|
|
92
|
+
end
|
|
93
|
+
|
|
17
94
|
def headers
|
|
18
95
|
{}
|
|
19
96
|
end
|
|
20
97
|
|
|
21
|
-
#
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
98
|
+
def guardrail_url # :nodoc:
|
|
99
|
+
identifier = @config.bedrock_guardrail_id
|
|
100
|
+
version = @config.bedrock_guardrail_version
|
|
101
|
+
if identifier.to_s.empty? || version.to_s.empty?
|
|
102
|
+
raise ConfigurationError, 'Bedrock moderation requires bedrock_guardrail_id and bedrock_guardrail_version'
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
identifier = URI.encode_www_form_component(identifier)
|
|
106
|
+
version = URI.encode_www_form_component(version)
|
|
107
|
+
"/guardrail/#{identifier}/version/#{version}/apply"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def batch_cost_multiplier(**) = 0.5
|
|
25
111
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
model: model,
|
|
32
|
-
params: normalized_params,
|
|
33
|
-
headers: headers,
|
|
34
|
-
schema: schema,
|
|
35
|
-
thinking: thinking,
|
|
36
|
-
&
|
|
37
|
-
)
|
|
112
|
+
def embedding_batch_protocol(model_id) # :nodoc:
|
|
113
|
+
case model_id
|
|
114
|
+
when 'amazon.titan-embed-text-v2:0' then protocols[:titan_text_embeddings]
|
|
115
|
+
when 'amazon.titan-embed-image-v1' then protocols[:titan_multimodal_embeddings]
|
|
116
|
+
end
|
|
38
117
|
end
|
|
39
|
-
# rubocop:enable Metrics/ParameterLists
|
|
40
118
|
|
|
41
119
|
def parse_error(response)
|
|
42
|
-
|
|
120
|
+
body = parse_error_body(response)
|
|
121
|
+
return unless body
|
|
122
|
+
return super unless body.is_a?(Hash)
|
|
43
123
|
|
|
44
|
-
body
|
|
45
|
-
|
|
124
|
+
body['message'] || body['Message'] || nested_error_message(body) || body['__type'] || super
|
|
125
|
+
end
|
|
46
126
|
|
|
47
|
-
|
|
127
|
+
# bedrock-mantle nests code, message, and type under "error" rather
|
|
128
|
+
# than answering with a bare string.
|
|
129
|
+
def nested_error_message(body)
|
|
130
|
+
error = body['error']
|
|
131
|
+
error.is_a?(Hash) ? error['message'] || error : error
|
|
48
132
|
end
|
|
49
133
|
|
|
50
134
|
def list_models
|
|
51
|
-
|
|
52
|
-
parse_list_models_response(response, slug, capabilities)
|
|
135
|
+
merge_mantle_models(list_converse_models, list_mantle_models)
|
|
53
136
|
end
|
|
54
137
|
|
|
55
138
|
class << self
|
|
56
139
|
def configuration_options
|
|
57
|
-
%i[
|
|
140
|
+
%i[
|
|
141
|
+
bedrock_api_key
|
|
142
|
+
bedrock_secret_key
|
|
143
|
+
bedrock_region
|
|
144
|
+
bedrock_session_token
|
|
145
|
+
bedrock_credential_provider
|
|
146
|
+
bedrock_api_base
|
|
147
|
+
bedrock_mantle_api_base
|
|
148
|
+
bedrock_batch_s3_uri
|
|
149
|
+
bedrock_batch_role_arn
|
|
150
|
+
bedrock_video_s3_uri
|
|
151
|
+
bedrock_guardrail_id
|
|
152
|
+
bedrock_guardrail_version
|
|
153
|
+
]
|
|
58
154
|
end
|
|
59
155
|
|
|
60
156
|
def configuration_requirements
|
|
61
|
-
%i[
|
|
157
|
+
%i[bedrock_region]
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def model_required?(operation:)
|
|
161
|
+
operation != :moderate
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def configured?(config)
|
|
165
|
+
!!(config.bedrock_region && credentials_configured?(config))
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def credentials_configured?(config)
|
|
169
|
+
return credential_provider?(config) if config.bedrock_credential_provider
|
|
170
|
+
|
|
171
|
+
!!(config.bedrock_api_key && config.bedrock_secret_key)
|
|
62
172
|
end
|
|
173
|
+
|
|
174
|
+
private
|
|
175
|
+
|
|
176
|
+
def credential_provider?(config)
|
|
177
|
+
config.bedrock_credential_provider&.respond_to?(:credentials)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def ensure_configured!
|
|
182
|
+
return if configured?
|
|
183
|
+
|
|
184
|
+
missing = []
|
|
185
|
+
missing << :bedrock_region unless @config.bedrock_region
|
|
186
|
+
missing << bedrock_credentials_requirement unless self.class.credentials_configured?(@config)
|
|
187
|
+
|
|
188
|
+
raise ConfigurationError, "Missing configuration for Bedrock: #{missing.join(', ')}"
|
|
63
189
|
end
|
|
64
190
|
|
|
65
191
|
private
|
|
66
192
|
|
|
193
|
+
def voxtral_transcription?(operation, model_id)
|
|
194
|
+
operation == :transcribe && model_id == 'mistral.voxtral-small-24b-2507'
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def batch_protocol_for(requests)
|
|
198
|
+
return super unless requests.any? { |request| request.key?(:text) }
|
|
199
|
+
|
|
200
|
+
kinds = requests.map { |request| embedding_batch_protocol(request.fetch(:model)) }.uniq
|
|
201
|
+
unless requests.all? { |request| request.key?(:text) } && kinds.one? && kinds.first
|
|
202
|
+
raise Error, 'Bedrock embedding batches require one supported Titan embedding model'
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
kinds.first
|
|
206
|
+
end
|
|
207
|
+
|
|
67
208
|
def bedrock_region
|
|
68
209
|
@config.bedrock_region
|
|
69
210
|
end
|
|
70
211
|
|
|
71
|
-
def
|
|
72
|
-
|
|
212
|
+
def bedrock_credentials_requirement
|
|
213
|
+
if @config.bedrock_credential_provider
|
|
214
|
+
'bedrock_credential_provider responding to #credentials'
|
|
215
|
+
else
|
|
216
|
+
'bedrock_credential_provider or bedrock_api_key + bedrock_secret_key'
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def list_converse_models
|
|
221
|
+
parse_list_models_response(signed_get(models_api_base, models_url), slug, profile_ids: inference_profile_ids)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def list_mantle_models
|
|
225
|
+
response = signed_get(mantle_api_base, mantle_models_url, service: Bedrock::Mantle::SIGNING_SERVICE)
|
|
226
|
+
parse_mantle_models_response(response, slug)
|
|
73
227
|
end
|
|
74
228
|
|
|
75
|
-
def
|
|
76
|
-
|
|
77
|
-
|
|
229
|
+
def mantle_protocol_for(model_id)
|
|
230
|
+
return protocols[:mantle_anthropic] if model_id.start_with?('anthropic.')
|
|
231
|
+
return protocols[:mantle_responses] if Bedrock::Mantle::RESPONSES_MODELS.include?(model_id)
|
|
232
|
+
|
|
233
|
+
protocols[:mantle_chat_completions]
|
|
234
|
+
end
|
|
78
235
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
236
|
+
def embedding_protocol_for(model_id)
|
|
237
|
+
case model_id
|
|
238
|
+
when bedrock_model_id_pattern('amazon.titan-embed-image')
|
|
239
|
+
protocols[:titan_multimodal_embeddings]
|
|
240
|
+
when bedrock_model_id_pattern('amazon.titan-embed-g1-text'),
|
|
241
|
+
bedrock_model_id_pattern('amazon.titan-embed-text')
|
|
242
|
+
protocols[:titan_text_embeddings]
|
|
243
|
+
when bedrock_model_id_pattern('cohere.embed')
|
|
244
|
+
protocols[:cohere_embeddings]
|
|
245
|
+
when bedrock_model_id_pattern('amazon.nova-2-multimodal-embeddings')
|
|
246
|
+
protocols[:nova_embeddings]
|
|
247
|
+
else
|
|
248
|
+
raise Error, "Bedrock embeddings are not supported for #{model_id.inspect}"
|
|
82
249
|
end
|
|
250
|
+
end
|
|
83
251
|
|
|
84
|
-
|
|
85
|
-
|
|
252
|
+
def image_protocol_for(model_id)
|
|
253
|
+
base_id = model_id.sub(/\A(?:#{Protocols::Converse::REGION_PREFIXES.join('|')})\./, '')
|
|
254
|
+
return protocols[:stability_images] if Protocols::InvokeModel::StabilityImages::MODELS.include?(base_id)
|
|
255
|
+
|
|
256
|
+
raise Error, "Bedrock image generation is not supported for #{model_id.inspect}"
|
|
86
257
|
end
|
|
87
258
|
|
|
88
|
-
def
|
|
89
|
-
|
|
259
|
+
def video_protocol_for(model_id)
|
|
260
|
+
return protocols[:async_videos] if model_id == 'luma.ray-v2:0'
|
|
261
|
+
|
|
262
|
+
raise Error, "Bedrock video generation is not supported for #{model_id.inspect}"
|
|
90
263
|
end
|
|
91
264
|
|
|
92
|
-
def
|
|
93
|
-
|
|
94
|
-
cleaned.delete(:tools)
|
|
95
|
-
cleaned
|
|
265
|
+
def bedrock_model_id_pattern(prefix)
|
|
266
|
+
/\A(?:(?:#{Protocols::Converse::REGION_PREFIXES.join('|')})\.)?#{Regexp.escape(prefix)}/
|
|
96
267
|
end
|
|
97
268
|
end
|
|
98
269
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
# Cohere API integration.
|
|
6
|
+
class Cohere < Provider
|
|
7
|
+
protocol :cohere, Protocols::Cohere
|
|
8
|
+
protocol :files, Protocols::Cohere::Datasets
|
|
9
|
+
|
|
10
|
+
def api_base
|
|
11
|
+
@config.cohere_api_base || 'https://api.cohere.com'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def headers
|
|
15
|
+
{
|
|
16
|
+
'Authorization' => "Bearer #{@config.cohere_api_key}"
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
def configuration_options
|
|
22
|
+
%i[cohere_api_key cohere_api_base]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def configuration_requirements
|
|
26
|
+
%i[cohere_api_key]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Providers
|
|
5
|
+
# Integrates Deepgram transcription and speech synthesis.
|
|
6
|
+
class Deepgram < Provider
|
|
7
|
+
protocol :deepgram, Protocols::Deepgram
|
|
8
|
+
|
|
9
|
+
def api_base
|
|
10
|
+
@config.deepgram_api_base || 'https://api.deepgram.com'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def headers
|
|
14
|
+
{ 'Authorization' => "Token #{@config.deepgram_api_key}" }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Deepgram reports failures as an err_msg alongside an err_code, which
|
|
18
|
+
# the generic error parser does not know to look for.
|
|
19
|
+
def parse_error(response)
|
|
20
|
+
body = parse_error_body(response)
|
|
21
|
+
return super unless body.is_a?(Hash)
|
|
22
|
+
|
|
23
|
+
body['err_msg'] || super
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
def configuration_options
|
|
28
|
+
%i[deepgram_api_key deepgram_api_base]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def configuration_requirements
|
|
32
|
+
%i[deepgram_api_key]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|