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/chunk.rb
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module RubyLLM
|
|
4
|
+
# A Chunk is one streamed fragment of an assistant response. Chunks are
|
|
5
|
+
# yielded to the block passed to Chat#ask or Chat#complete when streaming.
|
|
6
|
+
# A Chunk is a Message, so it responds to the same readers, but it holds
|
|
7
|
+
# only the data received in that part of the stream, such as a piece of
|
|
8
|
+
# content, partial tool calls, or the finish reason on the final chunk.
|
|
9
|
+
#
|
|
10
|
+
# chat.ask "Write a haiku about Ruby" do |chunk|
|
|
11
|
+
# print chunk.content
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
4
14
|
class Chunk < Message
|
|
5
15
|
end
|
|
6
16
|
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
# A Citation links a span of generated text to the source material that
|
|
5
|
+
# supports it. Providers return citations in different shapes. RubyLLM
|
|
6
|
+
# normalizes all of them into Citation objects on Message#citations.
|
|
7
|
+
# Fields a provider does not report are +nil+.
|
|
8
|
+
#
|
|
9
|
+
# chat = RubyLLM.chat(model: 'claude-sonnet-5').with_citations
|
|
10
|
+
# response = chat.ask "Who created Ruby?", with: "facts.txt"
|
|
11
|
+
#
|
|
12
|
+
# response.citations.each do |citation|
|
|
13
|
+
# citation.title # => "facts.txt"
|
|
14
|
+
# citation.cited_text # => the quoted passage from facts.txt
|
|
15
|
+
# citation.text # => the span of the answer it supports
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
class Citation
|
|
19
|
+
include Support::Inspectable
|
|
20
|
+
|
|
21
|
+
# The URL of the cited source, when citing the web, or +nil+.
|
|
22
|
+
attr_reader :url
|
|
23
|
+
|
|
24
|
+
# The title or filename of the cited source, or +nil+.
|
|
25
|
+
attr_reader :title
|
|
26
|
+
|
|
27
|
+
# The quoted snippet from the source material, or +nil+.
|
|
28
|
+
attr_reader :cited_text
|
|
29
|
+
|
|
30
|
+
# The span of the response content this citation supports, or +nil+.
|
|
31
|
+
attr_reader :text
|
|
32
|
+
|
|
33
|
+
# The character offset where the cited span starts in the response
|
|
34
|
+
# content, or +nil+.
|
|
35
|
+
#
|
|
36
|
+
# response.content[citation.start_index...citation.end_index] == citation.text # => true
|
|
37
|
+
#
|
|
38
|
+
attr_reader :start_index
|
|
39
|
+
|
|
40
|
+
# The character offset where the cited span ends in the response
|
|
41
|
+
# content, or +nil+.
|
|
42
|
+
attr_reader :end_index
|
|
43
|
+
|
|
44
|
+
# The provider's identifier for the cited source, or +nil+.
|
|
45
|
+
attr_reader :source_id
|
|
46
|
+
|
|
47
|
+
# The 0-indexed position of the source document or search result,
|
|
48
|
+
# or +nil+.
|
|
49
|
+
attr_reader :source_index
|
|
50
|
+
|
|
51
|
+
# The first page of a PDF citation (1-indexed, inclusive), or +nil+.
|
|
52
|
+
attr_reader :start_page
|
|
53
|
+
|
|
54
|
+
# The last page of a PDF citation (1-indexed, inclusive), or +nil+.
|
|
55
|
+
attr_reader :end_page
|
|
56
|
+
|
|
57
|
+
def initialize(options = {}) # :nodoc:
|
|
58
|
+
@url = options[:url]
|
|
59
|
+
@title = options[:title]
|
|
60
|
+
@cited_text = options[:cited_text]
|
|
61
|
+
@text = options[:text]
|
|
62
|
+
@start_index = options[:start_index]
|
|
63
|
+
@end_index = options[:end_index]
|
|
64
|
+
@source_id = options[:source_id]
|
|
65
|
+
@source_index = options[:source_index]
|
|
66
|
+
@start_page = options[:start_page]
|
|
67
|
+
@end_page = options[:end_page]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.from_h(data) # :nodoc:
|
|
71
|
+
new(Support::Utils.deep_symbolize_keys(data))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def inspect_attributes # :nodoc:
|
|
75
|
+
{ url: url, title: title, start_index: start_index, end_index: end_index }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Returns the citation as a Hash with symbol keys, omitting +nil+ fields.
|
|
79
|
+
def to_h
|
|
80
|
+
{
|
|
81
|
+
url: url,
|
|
82
|
+
title: title,
|
|
83
|
+
cited_text: cited_text,
|
|
84
|
+
text: text,
|
|
85
|
+
start_index: start_index,
|
|
86
|
+
end_index: end_index,
|
|
87
|
+
source_id: source_id,
|
|
88
|
+
source_index: source_index,
|
|
89
|
+
start_page: start_page,
|
|
90
|
+
end_page: end_page
|
|
91
|
+
}.compact
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Returns +true+ if +other+ is a Citation with the same attributes,
|
|
95
|
+
# +false+ otherwise.
|
|
96
|
+
def ==(other)
|
|
97
|
+
other.is_a?(Citation) && to_h == other.to_h
|
|
98
|
+
end
|
|
99
|
+
alias eql? == # :nodoc:
|
|
100
|
+
|
|
101
|
+
def hash # :nodoc:
|
|
102
|
+
to_h.hash
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -3,11 +3,29 @@
|
|
|
3
3
|
require 'logger'
|
|
4
4
|
|
|
5
5
|
module RubyLLM
|
|
6
|
-
#
|
|
6
|
+
# A Configuration holds every RubyLLM setting: provider credentials,
|
|
7
|
+
# default models, timeouts, retries, logging, and the model registry.
|
|
8
|
+
# The global instance is yielded by RubyLLM.configure and available as
|
|
9
|
+
# RubyLLM.config.
|
|
10
|
+
#
|
|
11
|
+
# RubyLLM.configure do |config|
|
|
12
|
+
# config.openai_api_key = ENV['OPENAI_API_KEY']
|
|
13
|
+
# config.anthropic_api_key = ENV['ANTHROPIC_API_KEY']
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# RubyLLM.context yields an isolated copy for per-request or per-tenant
|
|
17
|
+
# overrides.
|
|
18
|
+
#
|
|
19
|
+
# Provider credentials such as +openai_api_key+ are declared by each
|
|
20
|
+
# provider. See https://rubyllm.com/next/configuration-providers/ for
|
|
21
|
+
# provider credentials and endpoint settings.
|
|
22
|
+
#
|
|
23
|
+
# Assigning an empty or whitespace-only string to any option stores
|
|
24
|
+
# +nil+, so unset environment variables behave as if the option was
|
|
25
|
+
# never set.
|
|
7
26
|
class Configuration
|
|
8
27
|
class << self
|
|
9
|
-
|
|
10
|
-
def option(key, default = nil)
|
|
28
|
+
def option(key, default = nil) # :nodoc:
|
|
11
29
|
key = key.to_sym
|
|
12
30
|
return if options.include?(key)
|
|
13
31
|
|
|
@@ -22,10 +40,12 @@ module RubyLLM
|
|
|
22
40
|
defaults[key] = default
|
|
23
41
|
end
|
|
24
42
|
|
|
25
|
-
def register_provider_options(options)
|
|
43
|
+
def register_provider_options(options) # :nodoc:
|
|
26
44
|
Array(options).each { |key| option(key, nil) }
|
|
27
45
|
end
|
|
28
46
|
|
|
47
|
+
# Returns the names of all declared options as an array of symbols,
|
|
48
|
+
# including options registered by providers.
|
|
29
49
|
def options
|
|
30
50
|
option_keys.dup
|
|
31
51
|
end
|
|
@@ -40,55 +60,272 @@ module RubyLLM
|
|
|
40
60
|
# System-level options are declared here.
|
|
41
61
|
# Provider-specific options are declared in each provider class via
|
|
42
62
|
# `self.configuration_options` and registered through Provider.register.
|
|
43
|
-
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# :attr_accessor: default_model
|
|
66
|
+
#
|
|
67
|
+
# The model id used by RubyLLM.chat when no model is given.
|
|
68
|
+
# Default: <tt>'gpt-5.6'</tt>.
|
|
69
|
+
option :default_model, 'gpt-5.6'
|
|
70
|
+
|
|
71
|
+
##
|
|
72
|
+
# :attr_accessor: default_embedding_model
|
|
73
|
+
#
|
|
74
|
+
# The model id used by RubyLLM.embed when no model is given.
|
|
75
|
+
# Default: <tt>'text-embedding-3-small'</tt>.
|
|
44
76
|
option :default_embedding_model, 'text-embedding-3-small'
|
|
77
|
+
|
|
78
|
+
##
|
|
79
|
+
# :attr_accessor: default_moderation_model
|
|
80
|
+
#
|
|
81
|
+
# The model id used by RubyLLM.moderate when no model is given.
|
|
82
|
+
# Default: <tt>'omni-moderation-latest'</tt>.
|
|
45
83
|
option :default_moderation_model, 'omni-moderation-latest'
|
|
46
|
-
option :default_image_model, 'gpt-image-1.5'
|
|
47
|
-
option :default_transcription_model, 'whisper-1'
|
|
48
84
|
|
|
49
|
-
|
|
50
|
-
|
|
85
|
+
##
|
|
86
|
+
# :attr_accessor: default_image_model
|
|
87
|
+
#
|
|
88
|
+
# The model id used by RubyLLM.paint when no model is given.
|
|
89
|
+
# Default: <tt>'gpt-image-2'</tt>.
|
|
90
|
+
option :default_image_model, 'gpt-image-2'
|
|
91
|
+
|
|
92
|
+
##
|
|
93
|
+
# :attr_accessor: default_speech_model
|
|
94
|
+
#
|
|
95
|
+
# The model id used by RubyLLM.speak when no model is given.
|
|
96
|
+
# Default: <tt>'gpt-4o-mini-tts-2025-12-15'</tt>.
|
|
97
|
+
option :default_speech_model, 'gpt-4o-mini-tts-2025-12-15'
|
|
98
|
+
|
|
99
|
+
##
|
|
100
|
+
# :attr_accessor: default_transcription_model
|
|
101
|
+
#
|
|
102
|
+
# The model id used by RubyLLM.transcribe when no model is given.
|
|
103
|
+
# Default: <tt>'gpt-transcribe'</tt>.
|
|
104
|
+
option :default_transcription_model, 'gpt-transcribe'
|
|
105
|
+
|
|
106
|
+
##
|
|
107
|
+
# :attr_accessor: default_ocr_model
|
|
108
|
+
#
|
|
109
|
+
# The model id used by RubyLLM.ocr when no model is given.
|
|
110
|
+
# Default: <tt>'mistral-ocr-latest'</tt>.
|
|
111
|
+
option :default_ocr_model, 'mistral-ocr-latest'
|
|
112
|
+
|
|
113
|
+
##
|
|
114
|
+
# :attr_accessor: default_video_model
|
|
115
|
+
#
|
|
116
|
+
# The model id used by RubyLLM.animate when no model is given.
|
|
117
|
+
# Default: <tt>'grok-imagine-video-1.5'</tt>.
|
|
118
|
+
option :default_video_model, 'grok-imagine-video-1.5'
|
|
119
|
+
|
|
120
|
+
##
|
|
121
|
+
# :attr_accessor: video_generation_timeout
|
|
122
|
+
#
|
|
123
|
+
# Seconds RubyLLM.animate waits for a video job to finish before
|
|
124
|
+
# raising an error. Default: 600.
|
|
125
|
+
option :video_generation_timeout, 600
|
|
126
|
+
|
|
127
|
+
##
|
|
128
|
+
# :attr_accessor: video_generation_poll_interval
|
|
129
|
+
#
|
|
130
|
+
# Seconds between status polls while RubyLLM.animate waits for a
|
|
131
|
+
# video job. Default: 5.
|
|
132
|
+
option :video_generation_poll_interval, 5
|
|
51
133
|
|
|
52
|
-
|
|
53
|
-
|
|
134
|
+
##
|
|
135
|
+
# :attr_accessor: model_registry_file
|
|
136
|
+
#
|
|
137
|
+
# Path of the writable JSON cache holding the model registry. Defaults
|
|
138
|
+
# to the operating system's user cache directory. The copy bundled with
|
|
139
|
+
# the gem is used until this file exists.
|
|
140
|
+
option :model_registry_file, -> { Models::Registry.cache_path }
|
|
54
141
|
|
|
142
|
+
##
|
|
143
|
+
# :attr_accessor: model_registry_store
|
|
144
|
+
#
|
|
145
|
+
# Store object the model registry reads from and persists to. Rails
|
|
146
|
+
# apps using the acts_as helpers set this to the database store
|
|
147
|
+
# automatically. A store must respond to +read+, returning an array of
|
|
148
|
+
# Model entries, and may respond to +write(registry)+ to let
|
|
149
|
+
# Models#refresh persist. Default: +nil+ (use +model_registry_file+).
|
|
150
|
+
option :model_registry_store, nil
|
|
151
|
+
|
|
152
|
+
# Optional persistence adapter installed by the Rails integration.
|
|
153
|
+
option :batch_store, nil # :nodoc:
|
|
154
|
+
|
|
155
|
+
# Keeps custom 1.x initializers bootable long enough to run the 2.0
|
|
156
|
+
# upgrade generator. The registry is always RubyLLM-owned in 2.0.
|
|
157
|
+
def model_registry_class=(_value) # :nodoc:
|
|
158
|
+
RubyLLM.deprecator.warn(
|
|
159
|
+
'config.model_registry_class is ignored in RubyLLM 2.0; remove it from your initializer'
|
|
160
|
+
)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def use_new_acts_as=(_value) # :nodoc:
|
|
164
|
+
RubyLLM.deprecator.warn(
|
|
165
|
+
'config.use_new_acts_as is ignored in RubyLLM 2.0; remove it from your initializer'
|
|
166
|
+
)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
##
|
|
170
|
+
# :attr_accessor: request_timeout
|
|
171
|
+
#
|
|
172
|
+
# Seconds to wait for a response before timing out. Default: 300.
|
|
55
173
|
option :request_timeout, 300
|
|
174
|
+
|
|
175
|
+
##
|
|
176
|
+
# :attr_accessor: max_retries
|
|
177
|
+
#
|
|
178
|
+
# Number of times to retry failed requests. Default: 3.
|
|
56
179
|
option :max_retries, 3
|
|
180
|
+
|
|
181
|
+
##
|
|
182
|
+
# :attr_accessor: retry_interval
|
|
183
|
+
#
|
|
184
|
+
# Initial delay in seconds before the first retry. Default: 0.1.
|
|
57
185
|
option :retry_interval, 0.1
|
|
186
|
+
|
|
187
|
+
##
|
|
188
|
+
# :attr_accessor: retry_backoff_factor
|
|
189
|
+
#
|
|
190
|
+
# Multiplier applied to the retry delay after each attempt.
|
|
191
|
+
# Default: 2.
|
|
58
192
|
option :retry_backoff_factor, 2
|
|
193
|
+
|
|
194
|
+
##
|
|
195
|
+
# :attr_accessor: retry_interval_randomness
|
|
196
|
+
#
|
|
197
|
+
# Random jitter factor applied to retry delays. Default: 0.5.
|
|
59
198
|
option :retry_interval_randomness, 0.5
|
|
199
|
+
|
|
200
|
+
##
|
|
201
|
+
# :attr_accessor: retry_max_interval
|
|
202
|
+
#
|
|
203
|
+
# Longest delay in seconds to wait between retries, including delays
|
|
204
|
+
# requested by the provider through rate-limit headers. When a
|
|
205
|
+
# provider asks for a longer wait, the request fails immediately
|
|
206
|
+
# instead of sleeping. Default: 30.
|
|
207
|
+
option :retry_max_interval, 30
|
|
208
|
+
|
|
209
|
+
##
|
|
210
|
+
# :attr_accessor: http_proxy
|
|
211
|
+
#
|
|
212
|
+
# Proxy URL for all requests, such as
|
|
213
|
+
# <tt>'http://proxy.example.com:8080'</tt>. HTTP, authenticated, and
|
|
214
|
+
# SOCKS5 proxies are supported. Default: +nil+.
|
|
60
215
|
option :http_proxy, nil
|
|
216
|
+
|
|
217
|
+
##
|
|
218
|
+
# :attr_accessor: tool_concurrency
|
|
219
|
+
#
|
|
220
|
+
# How chats run multiple tool calls from one response: +false+ for
|
|
221
|
+
# sequential execution, +true+ or +:threads+ for threads, +:fibers+
|
|
222
|
+
# for fibers via the async gem. Default: +false+.
|
|
61
223
|
option :tool_concurrency, false
|
|
62
224
|
|
|
225
|
+
##
|
|
226
|
+
# :attr_accessor: auto_upload_large_files
|
|
227
|
+
#
|
|
228
|
+
# Whether oversized local attachments are uploaded to provider file
|
|
229
|
+
# storage automatically. Default: +true+.
|
|
230
|
+
option :auto_upload_large_files, true
|
|
231
|
+
|
|
232
|
+
##
|
|
233
|
+
# :attr_accessor: logger
|
|
234
|
+
#
|
|
235
|
+
# Logger receiving RubyLLM output. When set, it overrides #log_file
|
|
236
|
+
# and #log_level. Default: +nil+.
|
|
63
237
|
option :logger, nil
|
|
238
|
+
|
|
239
|
+
##
|
|
240
|
+
# :attr_accessor: instrumenter
|
|
241
|
+
#
|
|
242
|
+
# Object receiving instrumentation events. It must respond to
|
|
243
|
+
# <tt>instrument(name, payload)</tt> and accept an optional block,
|
|
244
|
+
# like ActiveSupport::Notifications, which Rails apps use
|
|
245
|
+
# automatically. Default: +nil+.
|
|
64
246
|
option :instrumenter, nil
|
|
247
|
+
|
|
248
|
+
##
|
|
249
|
+
# :attr_accessor: deprecation_behavior
|
|
250
|
+
#
|
|
251
|
+
# How deprecation warnings are handled: +:warn+, +:silence+, or
|
|
252
|
+
# +:raise+. Default: +:warn+.
|
|
65
253
|
option :deprecation_behavior, :warn
|
|
254
|
+
|
|
255
|
+
##
|
|
256
|
+
# :attr_accessor: faraday_adapter
|
|
257
|
+
#
|
|
258
|
+
# Faraday adapter used for HTTP requests. Default: +:net_http+.
|
|
66
259
|
option :faraday_adapter, :net_http
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
260
|
+
|
|
261
|
+
##
|
|
262
|
+
# :attr_accessor: log_file
|
|
263
|
+
#
|
|
264
|
+
# Destination for the built-in logger, a path or an IO.
|
|
265
|
+
# Defaults to the +RUBYLLM_LOG_FILE+ environment variable when set,
|
|
266
|
+
# <tt>$stdout</tt> otherwise.
|
|
267
|
+
option :log_file, -> { ENV.fetch('RUBYLLM_LOG_FILE', nil) || $stdout }
|
|
268
|
+
|
|
269
|
+
##
|
|
270
|
+
# :attr_accessor: log_level
|
|
271
|
+
#
|
|
272
|
+
# Severity of the built-in logger. Defaults to <tt>Logger::DEBUG</tt>
|
|
273
|
+
# when the +RUBYLLM_DEBUG+ environment variable says yes
|
|
274
|
+
# (<tt>true</tt>, <tt>1</tt>, <tt>yes</tt>, or <tt>on</tt>),
|
|
275
|
+
# <tt>Logger::INFO</tt> otherwise.
|
|
276
|
+
option :log_level, -> { env_says_yes?('RUBYLLM_DEBUG') ? Logger::DEBUG : Logger::INFO }
|
|
277
|
+
|
|
278
|
+
##
|
|
279
|
+
# :attr_accessor: log_stream_debug
|
|
280
|
+
#
|
|
281
|
+
# Whether raw streaming chunks are logged. Defaults to +true+ when the
|
|
282
|
+
# +RUBYLLM_STREAM_DEBUG+ environment variable says yes, +false+
|
|
283
|
+
# otherwise.
|
|
284
|
+
option :log_stream_debug, -> { env_says_yes?('RUBYLLM_STREAM_DEBUG') }
|
|
285
|
+
|
|
286
|
+
##
|
|
287
|
+
# :attr_accessor: log_regexp_timeout
|
|
288
|
+
#
|
|
289
|
+
# Timeout in seconds for the regular expressions that scrub logged
|
|
290
|
+
# payloads. Defaults to the global <tt>Regexp.timeout</tt>, or 1.0
|
|
291
|
+
# when none is set. Requires Ruby 3.2 or later; on older Rubies
|
|
292
|
+
# setting a value logs a warning.
|
|
70
293
|
option :log_regexp_timeout, -> { Regexp.respond_to?(:timeout) ? (Regexp.timeout || 1.0) : nil }
|
|
71
294
|
|
|
72
|
-
def initialize
|
|
295
|
+
def initialize # :nodoc:
|
|
73
296
|
self.class.send(:defaults).each do |key, default|
|
|
74
297
|
value = default.respond_to?(:call) ? instance_exec(&default) : default
|
|
75
298
|
public_send("#{key}=", value)
|
|
76
299
|
end
|
|
77
300
|
end
|
|
78
301
|
|
|
79
|
-
def instance_variables
|
|
80
|
-
super.reject { |ivar| ivar.to_s.match?(/_id|_key|_secret|_token$/) }
|
|
302
|
+
def instance_variables # :nodoc:
|
|
303
|
+
super.reject { |ivar| ivar.to_s.match?(/(_id|_key|_secret|_token|_credential_provider)$/) }
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# Object#inspect reads the instance variable table directly, so
|
|
307
|
+
# credentials only stay out of console and log output when #inspect is
|
|
308
|
+
# built from the redacted #instance_variables.
|
|
309
|
+
def inspect # :nodoc:
|
|
310
|
+
attributes = instance_variables.map { |ivar| "#{ivar}=#{instance_variable_get(ivar).inspect}" }
|
|
311
|
+
"#<#{self.class.name} #{attributes.join(', ')}>"
|
|
81
312
|
end
|
|
82
313
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
elsif Regexp.respond_to?(:timeout)
|
|
87
|
-
@log_regexp_timeout = value
|
|
88
|
-
else
|
|
314
|
+
remove_method :log_regexp_timeout=
|
|
315
|
+
def log_regexp_timeout=(value) # :nodoc:
|
|
316
|
+
if value && !Regexp.respond_to?(:timeout)
|
|
89
317
|
RubyLLM.logger.warn("log_regexp_timeout is not supported on Ruby #{RUBY_VERSION}")
|
|
90
|
-
@log_regexp_timeout = value
|
|
91
318
|
end
|
|
319
|
+
@log_regexp_timeout = value
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
private
|
|
323
|
+
|
|
324
|
+
# Whether the +name+ environment variable is set to something that means
|
|
325
|
+
# yes, so that <tt>RUBYLLM_DEBUG=false</tt> reads as off rather than as
|
|
326
|
+
# merely set.
|
|
327
|
+
def env_says_yes?(name)
|
|
328
|
+
%w[true 1 yes on].include?(ENV[name].to_s.strip.downcase)
|
|
92
329
|
end
|
|
93
330
|
end
|
|
94
331
|
end
|
data/lib/ruby_llm/context.rb
CHANGED
|
@@ -1,29 +1,151 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module RubyLLM
|
|
4
|
-
#
|
|
4
|
+
# A Context is an isolated configuration scope. It offers the same entry
|
|
5
|
+
# points as the top-level RubyLLM module but reads from its own
|
|
6
|
+
# Configuration copy instead of the global one, which suits multi-tenant
|
|
7
|
+
# applications and per-request overrides.
|
|
8
|
+
#
|
|
9
|
+
# Contexts are created with RubyLLM.context:
|
|
10
|
+
#
|
|
11
|
+
# ctx = RubyLLM.context do |config|
|
|
12
|
+
# config.openai_api_key = ENV.fetch('TENANT_OPENAI_API_KEY')
|
|
13
|
+
# config.request_timeout = 180
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# ctx.chat.ask "Explain Ruby blocks."
|
|
17
|
+
# ctx.paint("A paper boat in the rain").save("boat.png")
|
|
18
|
+
# ctx.transcribe("meeting.wav").text
|
|
19
|
+
#
|
|
20
|
+
# The global configuration is left untouched.
|
|
21
|
+
#
|
|
22
|
+
# Batch submission uses each chat's own configuration (a chat carries
|
|
23
|
+
# the config it was built with), so there is no context entry point for
|
|
24
|
+
# it. To look up an existing batch, where no chats carry the config,
|
|
25
|
+
# pass a context to Batch.find:
|
|
26
|
+
#
|
|
27
|
+
# RubyLLM::Batch.find(id, provider: :anthropic, context: ctx)
|
|
28
|
+
#
|
|
5
29
|
class Context
|
|
6
|
-
attr_reader :config
|
|
30
|
+
attr_reader :config # :nodoc:
|
|
7
31
|
|
|
8
|
-
def initialize(config)
|
|
32
|
+
def initialize(config) # :nodoc:
|
|
9
33
|
@config = config
|
|
10
|
-
@connections = {}
|
|
11
34
|
end
|
|
12
35
|
|
|
36
|
+
# Creates a new Chat that uses this context's configuration.
|
|
37
|
+
# Accepts the same arguments as RubyLLM.chat.
|
|
13
38
|
def chat(*args, **kwargs, &)
|
|
14
39
|
Chat.new(*args, **kwargs, context: self, &)
|
|
15
40
|
end
|
|
16
41
|
|
|
42
|
+
# Counts tokens using this context's configuration.
|
|
43
|
+
# Accepts the same arguments as RubyLLM.count_tokens.
|
|
44
|
+
def count_tokens(text, model: nil, provider: nil)
|
|
45
|
+
chat(model:, provider:).count_tokens(text)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Tokenizes plain text using this context's configuration.
|
|
49
|
+
# Accepts the same arguments as RubyLLM.tokenize.
|
|
50
|
+
def tokenize(*args, **kwargs)
|
|
51
|
+
Tokenization.tokenize(*args, **kwargs, context: self)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Runs a named workflow using this context's instrumenter. Accepts the same
|
|
55
|
+
# arguments as RubyLLM.workflow.
|
|
56
|
+
def workflow(name, id: nil, metadata: nil, &)
|
|
57
|
+
Workflow.new(name, id:, metadata:, config: config).run(&)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Generates embeddings using this context's configuration.
|
|
61
|
+
# Accepts the same arguments as RubyLLM.embed.
|
|
17
62
|
def embed(*args, **kwargs, &)
|
|
18
63
|
Embedding.embed(*args, **kwargs, context: self, &)
|
|
19
64
|
end
|
|
20
65
|
|
|
66
|
+
# Stages an embedding request using this context's configuration.
|
|
67
|
+
# Accepts the same arguments as RubyLLM.embed_later.
|
|
68
|
+
def embed_later(text, model: nil, provider: nil, dimensions: nil)
|
|
69
|
+
EmbeddingRequest.new(text, model:, provider:, dimensions:, context: self)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Generates an image using this context's configuration.
|
|
73
|
+
# Accepts the same arguments as RubyLLM.paint.
|
|
21
74
|
def paint(*args, **kwargs, &)
|
|
22
75
|
Image.paint(*args, **kwargs, context: self, &)
|
|
23
76
|
end
|
|
24
77
|
|
|
25
|
-
|
|
26
|
-
|
|
78
|
+
# Generates a video using this context's configuration, blocking
|
|
79
|
+
# until it is ready. Accepts the same arguments as RubyLLM.animate.
|
|
80
|
+
def animate(*args, **kwargs, &)
|
|
81
|
+
Video.animate(*args, **kwargs, context: self, &)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Submits a video generation job using this context's configuration.
|
|
85
|
+
# Accepts the same arguments as RubyLLM.animate_later.
|
|
86
|
+
def animate_later(*args, **kwargs, &)
|
|
87
|
+
VideoJob.animate_later(*args, **kwargs, context: self, &)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Runs content moderation using this context's configuration.
|
|
91
|
+
# Accepts the same arguments as RubyLLM.moderate.
|
|
92
|
+
def moderate(*args, **kwargs, &)
|
|
93
|
+
Moderation.moderate(*args, **kwargs, context: self, &)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Runs hosted research using this context's configuration.
|
|
97
|
+
# Accepts the same arguments as RubyLLM.research.
|
|
98
|
+
def research(*args, **kwargs)
|
|
99
|
+
ResearchJob.research(*args, **kwargs, context: self)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Submits hosted research using this context's configuration.
|
|
103
|
+
# Accepts the same arguments as RubyLLM.research_later.
|
|
104
|
+
def research_later(*args, **kwargs)
|
|
105
|
+
ResearchJob.research_later(*args, **kwargs, context: self)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Generates speech audio using this context's configuration. Given a
|
|
109
|
+
# block, yields SpeechChunk objects and returns the complete Speech.
|
|
110
|
+
# Accepts the same arguments as RubyLLM.speak.
|
|
111
|
+
def speak(*args, **kwargs, &)
|
|
112
|
+
Speech.speak(*args, **kwargs, context: self, &)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Transcribes audio using this context's configuration.
|
|
116
|
+
# Accepts the same arguments as RubyLLM.transcribe.
|
|
117
|
+
def transcribe(*args, **kwargs, &)
|
|
118
|
+
Transcription.transcribe(*args, **kwargs, context: self, &)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Extracts document text using this context's configuration.
|
|
122
|
+
# Accepts the same arguments as RubyLLM.ocr.
|
|
123
|
+
def ocr(*args, **kwargs, &)
|
|
124
|
+
OCR.ocr(*args, **kwargs, context: self, &)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Ranks documents using this context's configuration.
|
|
128
|
+
# Accepts the same arguments as RubyLLM.rerank.
|
|
129
|
+
def rerank(*args, **kwargs, &)
|
|
130
|
+
Rerank.rerank(*args, **kwargs, context: self, &)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Uploads a file to a provider using this context's configuration.
|
|
134
|
+
# Accepts the same arguments as RubyLLM.upload.
|
|
135
|
+
def upload(*args, **kwargs, &)
|
|
136
|
+
UploadedFile.upload(*args, **kwargs, context: self, &)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Downloads a provider-hosted file using this context's configuration.
|
|
140
|
+
# Accepts the same arguments as RubyLLM.download.
|
|
141
|
+
def download(*args, **kwargs, &)
|
|
142
|
+
UploadedFile.download(*args, **kwargs, context: self, &)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Creates a provider-side prompt cache using this context's
|
|
146
|
+
# configuration. Accepts the same arguments as RubyLLM.cache.
|
|
147
|
+
def cache(*args, **kwargs, &)
|
|
148
|
+
CachedContent.create(*args, **kwargs, context: self, &)
|
|
27
149
|
end
|
|
28
150
|
end
|
|
29
151
|
end
|