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
data/lib/ruby_llm/aliases.rb
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'json'
|
|
4
|
-
|
|
5
|
-
module RubyLLM
|
|
6
|
-
# Manages model aliases for provider-specific versions
|
|
7
|
-
class Aliases
|
|
8
|
-
class << self
|
|
9
|
-
def resolve(model_id, provider = nil)
|
|
10
|
-
return model_id unless aliases[model_id]
|
|
11
|
-
|
|
12
|
-
if provider
|
|
13
|
-
aliases[model_id][provider.to_s] || model_id
|
|
14
|
-
else
|
|
15
|
-
aliases[model_id].values.first || model_id
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def aliases
|
|
20
|
-
@aliases ||= load_aliases
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def aliases_file
|
|
24
|
-
File.expand_path('aliases.json', __dir__)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def load_aliases
|
|
28
|
-
if File.exist?(aliases_file)
|
|
29
|
-
JSON.parse(File.read(aliases_file))
|
|
30
|
-
else
|
|
31
|
-
{}
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Replaces the cached alias map from aliases.json.
|
|
36
|
-
def reload!
|
|
37
|
-
@aliases = load_aliases
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
data/lib/ruby_llm/connection.rb
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'faraday'
|
|
4
|
-
require 'faraday/multipart'
|
|
5
|
-
require 'faraday/retry'
|
|
6
|
-
require 'ruby_llm/error_middleware'
|
|
7
|
-
require 'timeout'
|
|
8
|
-
|
|
9
|
-
module RubyLLM
|
|
10
|
-
# Connection class for managing API connections to various providers.
|
|
11
|
-
class Connection
|
|
12
|
-
attr_reader :provider, :connection, :config
|
|
13
|
-
|
|
14
|
-
def self.basic(&)
|
|
15
|
-
Faraday.new do |f|
|
|
16
|
-
f.response :logger,
|
|
17
|
-
RubyLLM.logger,
|
|
18
|
-
bodies: false,
|
|
19
|
-
errors: true,
|
|
20
|
-
headers: false,
|
|
21
|
-
log_level: :debug
|
|
22
|
-
f.response :raise_error
|
|
23
|
-
yield f if block_given?
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def initialize(provider, config)
|
|
28
|
-
@provider = provider
|
|
29
|
-
@config = config
|
|
30
|
-
|
|
31
|
-
ensure_configured!
|
|
32
|
-
@connection ||= Faraday.new(provider.api_base) do |faraday|
|
|
33
|
-
setup_timeout(faraday)
|
|
34
|
-
setup_logging(faraday)
|
|
35
|
-
setup_retry(faraday)
|
|
36
|
-
setup_middleware(faraday)
|
|
37
|
-
setup_http_proxy(faraday)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def post(url, payload, &)
|
|
42
|
-
instrument_request(:post, url) do
|
|
43
|
-
@connection.post url, payload do |req|
|
|
44
|
-
req.headers.merge! provider_headers
|
|
45
|
-
yield req if block_given?
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def get(url, &)
|
|
51
|
-
instrument_request(:get, url) do
|
|
52
|
-
@connection.get url do |req|
|
|
53
|
-
req.headers.merge! provider_headers
|
|
54
|
-
yield req if block_given?
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def instance_variables
|
|
60
|
-
super - %i[@config @connection]
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
def provider_headers
|
|
66
|
-
@provider.respond_to?(:headers) ? @provider.headers : {}
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def instrument_request(method, url)
|
|
70
|
-
payload = {
|
|
71
|
-
provider: @provider.respond_to?(:slug) ? @provider.slug : @provider.class.name,
|
|
72
|
-
method: method,
|
|
73
|
-
url: url
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
RubyLLM.instrument('request.ruby_llm', payload, config: @config) do
|
|
77
|
-
response = yield
|
|
78
|
-
payload[:status] = response.status if response.respond_to?(:status)
|
|
79
|
-
response
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def setup_timeout(faraday)
|
|
84
|
-
faraday.options.timeout = @config.request_timeout
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def setup_logging(faraday)
|
|
88
|
-
faraday.response :logger,
|
|
89
|
-
RubyLLM.logger,
|
|
90
|
-
bodies: RubyLLM.logger.debug?,
|
|
91
|
-
errors: true,
|
|
92
|
-
headers: false,
|
|
93
|
-
log_level: :debug do |logger|
|
|
94
|
-
logger.filter(logging_regexp('[A-Za-z0-9+/=]{100,}'), '[BASE64 DATA]')
|
|
95
|
-
logger.filter(logging_regexp('[-\\d.e,\\s]{100,}'), '[EMBEDDINGS ARRAY]')
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def logging_regexp(pattern)
|
|
100
|
-
return Regexp.new(pattern) if @config.log_regexp_timeout.nil? || !Regexp.respond_to?(:timeout)
|
|
101
|
-
|
|
102
|
-
Regexp.new(pattern, timeout: @config.log_regexp_timeout)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def setup_retry(faraday)
|
|
106
|
-
faraday.request :retry, {
|
|
107
|
-
max: @config.max_retries,
|
|
108
|
-
interval: @config.retry_interval,
|
|
109
|
-
interval_randomness: @config.retry_interval_randomness,
|
|
110
|
-
backoff_factor: @config.retry_backoff_factor,
|
|
111
|
-
methods: Faraday::Retry::Middleware::IDEMPOTENT_METHODS + [:post],
|
|
112
|
-
exceptions: retry_exceptions
|
|
113
|
-
}
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def setup_middleware(faraday)
|
|
117
|
-
faraday.request :multipart
|
|
118
|
-
faraday.request :json
|
|
119
|
-
faraday.response :json
|
|
120
|
-
adapter = @config.respond_to?(:faraday_adapter) ? @config.faraday_adapter : :net_http
|
|
121
|
-
faraday.adapter(adapter || :net_http)
|
|
122
|
-
faraday.use :llm_errors, provider: @provider
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def setup_http_proxy(faraday)
|
|
126
|
-
return unless @config.http_proxy
|
|
127
|
-
|
|
128
|
-
faraday.proxy = @config.http_proxy
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def retry_exceptions
|
|
132
|
-
[
|
|
133
|
-
Errno::ETIMEDOUT,
|
|
134
|
-
Timeout::Error,
|
|
135
|
-
Faraday::TimeoutError,
|
|
136
|
-
Faraday::ConnectionFailed,
|
|
137
|
-
Faraday::RetriableResponse,
|
|
138
|
-
RubyLLM::RateLimitError,
|
|
139
|
-
RubyLLM::ServerError,
|
|
140
|
-
RubyLLM::ServiceUnavailableError,
|
|
141
|
-
RubyLLM::OverloadedError
|
|
142
|
-
]
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def ensure_configured!
|
|
146
|
-
return if @provider.configured?
|
|
147
|
-
|
|
148
|
-
missing = @provider.configuration_requirements.reject { |req| @config.send(req) }
|
|
149
|
-
config_block = <<~RUBY
|
|
150
|
-
RubyLLM.configure do |config|
|
|
151
|
-
#{missing.map { |key| "config.#{key} = ENV['#{key.to_s.upcase}']" }.join("\n ")}
|
|
152
|
-
end
|
|
153
|
-
RUBY
|
|
154
|
-
|
|
155
|
-
raise ConfigurationError,
|
|
156
|
-
"#{@provider.name} provider is not configured. Add this to your initialization:\n\n#{config_block}"
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
end
|
data/lib/ruby_llm/content.rb
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
# Represents the content sent to or received from an LLM.
|
|
5
|
-
class Content
|
|
6
|
-
attr_reader :text, :attachments
|
|
7
|
-
|
|
8
|
-
def initialize(text = nil, attachments = nil)
|
|
9
|
-
@text = text
|
|
10
|
-
@attachments = []
|
|
11
|
-
|
|
12
|
-
process_attachments(attachments)
|
|
13
|
-
raise ArgumentError, 'Text and attachments cannot be both nil' if @text.nil? && @attachments.empty?
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def add_attachment(source, filename: nil)
|
|
17
|
-
@attachments << build_attachment(source, filename:)
|
|
18
|
-
self
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def format
|
|
22
|
-
if @text && @attachments.empty?
|
|
23
|
-
@text
|
|
24
|
-
else
|
|
25
|
-
self
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def empty?
|
|
30
|
-
attachments.empty? && (@text.nil? || (@text.respond_to?(:empty?) && @text.empty?))
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# For Rails serialization
|
|
34
|
-
def to_h
|
|
35
|
-
{ text: @text, attachments: @attachments.map(&:to_h) }
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
def build_attachment(source, filename: nil)
|
|
41
|
-
if source.is_a?(Attachment)
|
|
42
|
-
return source unless filename
|
|
43
|
-
|
|
44
|
-
return Attachment.new(source.source, filename:)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
Attachment.new(source, filename:)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def process_attachments_array_or_string(attachments)
|
|
51
|
-
Utils.to_safe_array(attachments).each do |file|
|
|
52
|
-
next if blank_attachment_entry?(file)
|
|
53
|
-
|
|
54
|
-
add_attachment(file)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def blank_attachment_entry?(file)
|
|
59
|
-
file.nil? || (file.is_a?(String) && file.strip.empty?)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def process_attachments(attachments)
|
|
63
|
-
if attachments.is_a?(Hash)
|
|
64
|
-
attachments.each_value { |attachment| process_attachments_array_or_string(attachment) }
|
|
65
|
-
else
|
|
66
|
-
process_attachments_array_or_string attachments
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
class Content
|
|
72
|
-
# Represents provider-specific payloads that should bypass RubyLLM formatting.
|
|
73
|
-
class Raw
|
|
74
|
-
attr_reader :value
|
|
75
|
-
|
|
76
|
-
def initialize(value)
|
|
77
|
-
raise ArgumentError, 'Raw content payload cannot be nil' if value.nil?
|
|
78
|
-
|
|
79
|
-
@value = value
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def format
|
|
83
|
-
@value
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def to_h
|
|
87
|
-
@value
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
data/lib/ruby_llm/deprecator.rb
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
# Owns RubyLLM deprecation warnings so applications and tests can decide how
|
|
5
|
-
# aggressively to handle compatibility paths.
|
|
6
|
-
class Deprecator
|
|
7
|
-
def warn(message)
|
|
8
|
-
case RubyLLM.config.deprecation_behavior
|
|
9
|
-
when :silence
|
|
10
|
-
nil
|
|
11
|
-
when :raise
|
|
12
|
-
raise DeprecationError, message
|
|
13
|
-
else
|
|
14
|
-
RubyLLM.logger.warn(message)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def deprecate(name, replacement:, removal:)
|
|
19
|
-
warn("#{name} is deprecated and will be removed in RubyLLM #{removal}. Use #{replacement} instead.")
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
class DeprecationError < StandardError; end
|
|
24
|
-
end
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'faraday'
|
|
4
|
-
require 'ruby_llm/error'
|
|
5
|
-
|
|
6
|
-
module RubyLLM
|
|
7
|
-
# Faraday middleware that maps provider-specific API errors to RubyLLM errors.
|
|
8
|
-
class ErrorMiddleware < Faraday::Middleware
|
|
9
|
-
def initialize(app, options = {})
|
|
10
|
-
super(app)
|
|
11
|
-
@provider = options[:provider]
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def call(env)
|
|
15
|
-
@app.call(env).on_complete do |response|
|
|
16
|
-
self.class.parse_error(provider: @provider, response: response)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
class << self
|
|
21
|
-
CONTEXT_LENGTH_PATTERNS = [
|
|
22
|
-
/context length/i,
|
|
23
|
-
/context window/i,
|
|
24
|
-
/maximum context/i,
|
|
25
|
-
/request too large/i,
|
|
26
|
-
/too many tokens/i,
|
|
27
|
-
/token count exceeds/i,
|
|
28
|
-
/input[_\s-]?token/i,
|
|
29
|
-
/input or output tokens? must be reduced/i,
|
|
30
|
-
/reduce the length of messages/i,
|
|
31
|
-
/prompt is too long/i
|
|
32
|
-
].freeze
|
|
33
|
-
|
|
34
|
-
def parse_error(provider:, response:) # rubocop:disable Metrics/PerceivedComplexity
|
|
35
|
-
message = provider&.parse_error(response)
|
|
36
|
-
|
|
37
|
-
case response.status
|
|
38
|
-
when 200..399
|
|
39
|
-
message
|
|
40
|
-
when 400
|
|
41
|
-
if context_length_exceeded?(message)
|
|
42
|
-
raise ContextLengthExceededError.new(response, message || 'Context length exceeded')
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
raise BadRequestError.new(response, message || 'Invalid request - please check your input')
|
|
46
|
-
when 401
|
|
47
|
-
raise UnauthorizedError.new(response, message || 'Invalid API key - check your credentials')
|
|
48
|
-
when 402
|
|
49
|
-
raise PaymentRequiredError.new(response, message || 'Payment required - please top up your account')
|
|
50
|
-
when 403
|
|
51
|
-
raise ForbiddenError.new(response,
|
|
52
|
-
message || 'Forbidden - you do not have permission to access this resource')
|
|
53
|
-
when 429
|
|
54
|
-
if context_length_exceeded?(message)
|
|
55
|
-
raise ContextLengthExceededError.new(response, message || 'Context length exceeded')
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
raise RateLimitError.new(response, message || 'Rate limit exceeded - please wait a moment')
|
|
59
|
-
when 500
|
|
60
|
-
raise ServerError.new(response, message || 'API server error - please try again')
|
|
61
|
-
when 502..504
|
|
62
|
-
raise ServiceUnavailableError.new(response, message || 'API server unavailable - please try again later')
|
|
63
|
-
when 529
|
|
64
|
-
raise OverloadedError.new(response, message || 'Service overloaded - please try again later')
|
|
65
|
-
else
|
|
66
|
-
raise Error.new(response, message || 'An unknown error occurred')
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
private
|
|
71
|
-
|
|
72
|
-
def context_length_exceeded?(message)
|
|
73
|
-
return false if message.to_s.empty?
|
|
74
|
-
|
|
75
|
-
CONTEXT_LENGTH_PATTERNS.any? { |pattern| message.match?(pattern) }
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
Faraday::Middleware.register_middleware(llm_errors: RubyLLM::ErrorMiddleware)
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
# Emits structured RubyLLM events without requiring a specific observability
|
|
5
|
-
# backend. Rails apps can use ActiveSupport::Notifications as the instrumenter.
|
|
6
|
-
module Instrumentation
|
|
7
|
-
module_function
|
|
8
|
-
|
|
9
|
-
def instrument(name, payload = nil, config: nil, **attributes)
|
|
10
|
-
payload = build_payload(payload, attributes)
|
|
11
|
-
instrumenter = instrumenter_for(config)
|
|
12
|
-
return yield(payload) if block_given? && !instrumenter
|
|
13
|
-
|
|
14
|
-
unless instrumenter.respond_to?(:instrument)
|
|
15
|
-
return yield(payload) if block_given?
|
|
16
|
-
|
|
17
|
-
return
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
if block_given?
|
|
21
|
-
instrumenter.instrument(name, payload) { yield(payload) }
|
|
22
|
-
else
|
|
23
|
-
instrumenter.instrument(name, payload)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def build_payload(payload, attributes)
|
|
28
|
-
payload ||= {}
|
|
29
|
-
attributes.empty? ? payload : payload.merge(attributes)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def instrumenter_for(config)
|
|
33
|
-
(config || RubyLLM.config).instrumenter
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
data/lib/ruby_llm/mime_type.rb
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'marcel'
|
|
4
|
-
|
|
5
|
-
module RubyLLM
|
|
6
|
-
# MimeTypes module provides methods to handle MIME types using Marcel gem
|
|
7
|
-
module MimeType
|
|
8
|
-
module_function
|
|
9
|
-
|
|
10
|
-
def for(...)
|
|
11
|
-
Marcel::MimeType.for(...)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def image?(type)
|
|
15
|
-
type.start_with?('image/')
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def video?(type)
|
|
19
|
-
type.start_with?('video/')
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def audio?(type)
|
|
23
|
-
type.start_with?('audio/')
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def pdf?(type)
|
|
27
|
-
type == 'application/pdf'
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def document?(type)
|
|
31
|
-
return false if pdf?(type) || text?(type)
|
|
32
|
-
|
|
33
|
-
DOCUMENT_MIME_TYPES.include?(type) ||
|
|
34
|
-
DOCUMENT_MIME_PREFIXES.any? { |prefix| type.start_with?(prefix) }
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def text?(type)
|
|
38
|
-
type.start_with?('text/') ||
|
|
39
|
-
TEXT_SUFFIXES.any? { |suffix| type.end_with?(suffix) } ||
|
|
40
|
-
NON_TEXT_PREFIX_TEXT_MIME_TYPES.include?(type)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# MIME types that have a text/ prefix but need to be handled differently
|
|
44
|
-
TEXT_SUFFIXES = ['+json', '+xml', '+html', '+yaml', '+csv', '+plain', '+javascript', '+svg'].freeze
|
|
45
|
-
|
|
46
|
-
# MIME types that don't have a text/ prefix but should be treated as text
|
|
47
|
-
NON_TEXT_PREFIX_TEXT_MIME_TYPES = [
|
|
48
|
-
'application/json', # Base type, even if specific ones end with +json
|
|
49
|
-
'application/xml', # Base type, even if specific ones end with +xml
|
|
50
|
-
'application/javascript',
|
|
51
|
-
'application/ecmascript',
|
|
52
|
-
'application/rtf',
|
|
53
|
-
'application/sql',
|
|
54
|
-
'application/x-sh',
|
|
55
|
-
'application/x-csh',
|
|
56
|
-
'application/x-httpd-php',
|
|
57
|
-
'application/sdp',
|
|
58
|
-
'application/sparql-query',
|
|
59
|
-
'application/graphql',
|
|
60
|
-
'application/yang', # Data modeling language, often serialized as XML/JSON but the type itself is distinct
|
|
61
|
-
'application/mbox', # Mailbox format
|
|
62
|
-
'application/x-tex',
|
|
63
|
-
'application/x-latex',
|
|
64
|
-
'application/x-perl',
|
|
65
|
-
'application/x-python',
|
|
66
|
-
'application/x-tcl',
|
|
67
|
-
'application/pgp-signature', # Often ASCII armored
|
|
68
|
-
'application/pgp-keys', # Often ASCII armored
|
|
69
|
-
'application/vnd.coffeescript',
|
|
70
|
-
'application/vnd.dart',
|
|
71
|
-
'application/vnd.oai.openapi', # Base for OpenAPI, often with +json or +yaml suffix
|
|
72
|
-
'application/vnd.zul', # ZK User Interface Language (can be XML-like)
|
|
73
|
-
'application/x-yaml', # Common non-standard for YAML
|
|
74
|
-
'application/yaml', # Standard for YAML
|
|
75
|
-
'application/toml' # TOML configuration files
|
|
76
|
-
].freeze
|
|
77
|
-
|
|
78
|
-
DOCUMENT_MIME_TYPES = [
|
|
79
|
-
'application/msword',
|
|
80
|
-
'application/rtf',
|
|
81
|
-
'application/vnd.apple.keynote',
|
|
82
|
-
'application/vnd.apple.numbers',
|
|
83
|
-
'application/vnd.apple.pages',
|
|
84
|
-
'application/vnd.google-apps.document',
|
|
85
|
-
'application/vnd.google-apps.presentation',
|
|
86
|
-
'application/vnd.google-apps.spreadsheet',
|
|
87
|
-
'application/vnd.ms-excel',
|
|
88
|
-
'application/vnd.ms-powerpoint'
|
|
89
|
-
].freeze
|
|
90
|
-
|
|
91
|
-
DOCUMENT_MIME_PREFIXES = [
|
|
92
|
-
'application/vnd.openxmlformats-officedocument.',
|
|
93
|
-
'application/vnd.oasis.opendocument.'
|
|
94
|
-
].freeze
|
|
95
|
-
end
|
|
96
|
-
end
|
data/lib/ruby_llm/model/info.rb
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyLLM
|
|
4
|
-
module Model
|
|
5
|
-
# Information about an AI model's capabilities, pricing, and metadata.
|
|
6
|
-
class Info
|
|
7
|
-
attr_reader :id, :name, :provider, :family, :created_at, :context_window, :max_output_tokens, :knowledge_cutoff,
|
|
8
|
-
:modalities, :capabilities, :pricing, :metadata, :reasoning_options
|
|
9
|
-
|
|
10
|
-
# Create a default model with assumed capabilities
|
|
11
|
-
def self.default(model_id, provider)
|
|
12
|
-
new(
|
|
13
|
-
id: model_id,
|
|
14
|
-
name: model_id.tr('-', ' ').capitalize,
|
|
15
|
-
provider: provider,
|
|
16
|
-
capabilities: %w[function_calling streaming vision structured_output],
|
|
17
|
-
modalities: { input: %w[text image], output: %w[text] },
|
|
18
|
-
metadata: { warning: 'Assuming model exists, capabilities may not be accurate' }
|
|
19
|
-
)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def initialize(data)
|
|
23
|
-
@id = data[:id]
|
|
24
|
-
@name = data[:name]
|
|
25
|
-
@provider = data[:provider]
|
|
26
|
-
@family = data[:family]
|
|
27
|
-
@created_at = Utils.to_time(data[:created_at])&.utc
|
|
28
|
-
@context_window = data[:context_window]
|
|
29
|
-
@max_output_tokens = data[:max_output_tokens]
|
|
30
|
-
@knowledge_cutoff = Utils.to_date(data[:knowledge_cutoff])
|
|
31
|
-
@modalities = Modalities.new(data[:modalities] || {})
|
|
32
|
-
@capabilities = data[:capabilities] || []
|
|
33
|
-
@pricing = Pricing.new(data[:pricing] || {})
|
|
34
|
-
@metadata = data[:metadata]&.dup || {}
|
|
35
|
-
@reasoning_options = normalize_reasoning_options(reasoning_options_from(data))
|
|
36
|
-
store_reasoning_options_metadata
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def supports?(capability)
|
|
40
|
-
capabilities.include?(capability.to_s)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
%w[function_calling structured_output batch reasoning citations streaming].each do |cap|
|
|
44
|
-
define_method "#{cap}?" do
|
|
45
|
-
supports?(cap)
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def display_name
|
|
50
|
-
name
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def label
|
|
54
|
-
provider_name = provider_class&.name || provider
|
|
55
|
-
"#{provider_name} - #{display_name}"
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def max_tokens
|
|
59
|
-
max_output_tokens
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def supports_vision?
|
|
63
|
-
modalities.input.include?('image')
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def reasoning_option(type)
|
|
67
|
-
reasoning_options.find { |option| option[:type] == type.to_s }
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def reasoning_option_values(type)
|
|
71
|
-
Array(reasoning_option(type)&.fetch(:values, nil))
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def supports_video?
|
|
75
|
-
modalities.input.include?('video')
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def supports_functions?
|
|
79
|
-
function_calling?
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def input_price_per_million
|
|
83
|
-
pricing.text_tokens.input
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def output_price_per_million
|
|
87
|
-
pricing.text_tokens.output
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def cache_read_input_price_per_million
|
|
91
|
-
pricing.text_tokens.cache_read_input
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def cache_write_input_price_per_million
|
|
95
|
-
pricing.text_tokens.cache_write_input
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
alias cached_input_price_per_million cache_read_input_price_per_million
|
|
99
|
-
alias cache_creation_input_price_per_million cache_write_input_price_per_million
|
|
100
|
-
|
|
101
|
-
def cost_for(tokens)
|
|
102
|
-
tokens = tokens.tokens if tokens.respond_to?(:tokens)
|
|
103
|
-
|
|
104
|
-
Cost.new(tokens:, model: self)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def provider_class
|
|
108
|
-
RubyLLM::Provider.resolve provider
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def type
|
|
112
|
-
output = modalities.output
|
|
113
|
-
return 'embedding' if output.include?('embeddings')
|
|
114
|
-
return 'moderation' if output.include?('moderation')
|
|
115
|
-
return 'image' if output.include?('image')
|
|
116
|
-
return 'audio' if output.include?('audio')
|
|
117
|
-
return 'video' if output.include?('video')
|
|
118
|
-
|
|
119
|
-
'chat'
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def to_h
|
|
123
|
-
{
|
|
124
|
-
id: id,
|
|
125
|
-
name: name,
|
|
126
|
-
provider: provider,
|
|
127
|
-
family: family,
|
|
128
|
-
created_at: created_at,
|
|
129
|
-
context_window: context_window,
|
|
130
|
-
max_output_tokens: max_output_tokens,
|
|
131
|
-
knowledge_cutoff: knowledge_cutoff,
|
|
132
|
-
modalities: modalities.to_h,
|
|
133
|
-
capabilities: capabilities,
|
|
134
|
-
pricing: pricing.to_h,
|
|
135
|
-
metadata: metadata
|
|
136
|
-
}
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
private
|
|
140
|
-
|
|
141
|
-
def reasoning_options_from(data)
|
|
142
|
-
data[:reasoning_options] || metadata[:reasoning_options] || metadata['reasoning_options']
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def store_reasoning_options_metadata
|
|
146
|
-
return unless reasoning_options.any?
|
|
147
|
-
|
|
148
|
-
metadata.delete('reasoning_options')
|
|
149
|
-
metadata[:reasoning_options] = reasoning_options
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def normalize_reasoning_options(options)
|
|
153
|
-
Array(options).filter_map do |option|
|
|
154
|
-
next unless option.is_a?(Hash)
|
|
155
|
-
|
|
156
|
-
normalized = option.to_h.transform_keys(&:to_sym)
|
|
157
|
-
normalized[:type] = normalized[:type].to_s if normalized[:type]
|
|
158
|
-
normalized[:values] = Array(normalized[:values]).map(&:to_s) if normalized.key?(:values)
|
|
159
|
-
normalized
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|