ruby_llm_swarm 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +175 -0
  4. data/lib/generators/ruby_llm/chat_ui/chat_ui_generator.rb +187 -0
  5. data/lib/generators/ruby_llm/chat_ui/templates/controllers/chats_controller.rb.tt +39 -0
  6. data/lib/generators/ruby_llm/chat_ui/templates/controllers/messages_controller.rb.tt +24 -0
  7. data/lib/generators/ruby_llm/chat_ui/templates/controllers/models_controller.rb.tt +14 -0
  8. data/lib/generators/ruby_llm/chat_ui/templates/jobs/chat_response_job.rb.tt +12 -0
  9. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_chat.html.erb.tt +16 -0
  10. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_form.html.erb.tt +29 -0
  11. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/index.html.erb.tt +16 -0
  12. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/new.html.erb.tt +11 -0
  13. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/show.html.erb.tt +23 -0
  14. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_content.html.erb.tt +1 -0
  15. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_form.html.erb.tt +21 -0
  16. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_message.html.erb.tt +13 -0
  17. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_tool_calls.html.erb.tt +7 -0
  18. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt +9 -0
  19. data/lib/generators/ruby_llm/chat_ui/templates/views/models/_model.html.erb.tt +16 -0
  20. data/lib/generators/ruby_llm/chat_ui/templates/views/models/index.html.erb.tt +28 -0
  21. data/lib/generators/ruby_llm/chat_ui/templates/views/models/show.html.erb.tt +18 -0
  22. data/lib/generators/ruby_llm/generator_helpers.rb +194 -0
  23. data/lib/generators/ruby_llm/install/install_generator.rb +106 -0
  24. data/lib/generators/ruby_llm/install/templates/add_references_to_chats_tool_calls_and_messages_migration.rb.tt +9 -0
  25. data/lib/generators/ruby_llm/install/templates/chat_model.rb.tt +3 -0
  26. data/lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt +7 -0
  27. data/lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt +16 -0
  28. data/lib/generators/ruby_llm/install/templates/create_models_migration.rb.tt +45 -0
  29. data/lib/generators/ruby_llm/install/templates/create_tool_calls_migration.rb.tt +20 -0
  30. data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +12 -0
  31. data/lib/generators/ruby_llm/install/templates/message_model.rb.tt +4 -0
  32. data/lib/generators/ruby_llm/install/templates/model_model.rb.tt +3 -0
  33. data/lib/generators/ruby_llm/install/templates/tool_call_model.rb.tt +3 -0
  34. data/lib/generators/ruby_llm/upgrade_to_v1_7/templates/migration.rb.tt +145 -0
  35. data/lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +124 -0
  36. data/lib/generators/ruby_llm/upgrade_to_v1_9/templates/add_v1_9_message_columns.rb.tt +15 -0
  37. data/lib/generators/ruby_llm/upgrade_to_v1_9/upgrade_to_v1_9_generator.rb +49 -0
  38. data/lib/ruby_llm/active_record/acts_as.rb +174 -0
  39. data/lib/ruby_llm/active_record/acts_as_legacy.rb +384 -0
  40. data/lib/ruby_llm/active_record/chat_methods.rb +350 -0
  41. data/lib/ruby_llm/active_record/message_methods.rb +81 -0
  42. data/lib/ruby_llm/active_record/model_methods.rb +84 -0
  43. data/lib/ruby_llm/aliases.json +295 -0
  44. data/lib/ruby_llm/aliases.rb +38 -0
  45. data/lib/ruby_llm/attachment.rb +220 -0
  46. data/lib/ruby_llm/chat.rb +816 -0
  47. data/lib/ruby_llm/chunk.rb +6 -0
  48. data/lib/ruby_llm/configuration.rb +78 -0
  49. data/lib/ruby_llm/connection.rb +126 -0
  50. data/lib/ruby_llm/content.rb +73 -0
  51. data/lib/ruby_llm/context.rb +29 -0
  52. data/lib/ruby_llm/embedding.rb +29 -0
  53. data/lib/ruby_llm/error.rb +84 -0
  54. data/lib/ruby_llm/image.rb +49 -0
  55. data/lib/ruby_llm/message.rb +86 -0
  56. data/lib/ruby_llm/mime_type.rb +71 -0
  57. data/lib/ruby_llm/model/info.rb +111 -0
  58. data/lib/ruby_llm/model/modalities.rb +22 -0
  59. data/lib/ruby_llm/model/pricing.rb +48 -0
  60. data/lib/ruby_llm/model/pricing_category.rb +46 -0
  61. data/lib/ruby_llm/model/pricing_tier.rb +33 -0
  62. data/lib/ruby_llm/model.rb +7 -0
  63. data/lib/ruby_llm/models.json +33198 -0
  64. data/lib/ruby_llm/models.rb +231 -0
  65. data/lib/ruby_llm/models_schema.json +168 -0
  66. data/lib/ruby_llm/moderation.rb +56 -0
  67. data/lib/ruby_llm/provider.rb +243 -0
  68. data/lib/ruby_llm/providers/anthropic/capabilities.rb +134 -0
  69. data/lib/ruby_llm/providers/anthropic/chat.rb +125 -0
  70. data/lib/ruby_llm/providers/anthropic/content.rb +44 -0
  71. data/lib/ruby_llm/providers/anthropic/embeddings.rb +20 -0
  72. data/lib/ruby_llm/providers/anthropic/media.rb +92 -0
  73. data/lib/ruby_llm/providers/anthropic/models.rb +63 -0
  74. data/lib/ruby_llm/providers/anthropic/streaming.rb +45 -0
  75. data/lib/ruby_llm/providers/anthropic/tools.rb +109 -0
  76. data/lib/ruby_llm/providers/anthropic.rb +36 -0
  77. data/lib/ruby_llm/providers/bedrock/capabilities.rb +167 -0
  78. data/lib/ruby_llm/providers/bedrock/chat.rb +63 -0
  79. data/lib/ruby_llm/providers/bedrock/media.rb +61 -0
  80. data/lib/ruby_llm/providers/bedrock/models.rb +98 -0
  81. data/lib/ruby_llm/providers/bedrock/signing.rb +831 -0
  82. data/lib/ruby_llm/providers/bedrock/streaming/base.rb +51 -0
  83. data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +71 -0
  84. data/lib/ruby_llm/providers/bedrock/streaming/message_processing.rb +67 -0
  85. data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +80 -0
  86. data/lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb +78 -0
  87. data/lib/ruby_llm/providers/bedrock/streaming.rb +18 -0
  88. data/lib/ruby_llm/providers/bedrock.rb +82 -0
  89. data/lib/ruby_llm/providers/deepseek/capabilities.rb +130 -0
  90. data/lib/ruby_llm/providers/deepseek/chat.rb +16 -0
  91. data/lib/ruby_llm/providers/deepseek.rb +30 -0
  92. data/lib/ruby_llm/providers/gemini/capabilities.rb +281 -0
  93. data/lib/ruby_llm/providers/gemini/chat.rb +454 -0
  94. data/lib/ruby_llm/providers/gemini/embeddings.rb +37 -0
  95. data/lib/ruby_llm/providers/gemini/images.rb +47 -0
  96. data/lib/ruby_llm/providers/gemini/media.rb +112 -0
  97. data/lib/ruby_llm/providers/gemini/models.rb +40 -0
  98. data/lib/ruby_llm/providers/gemini/streaming.rb +61 -0
  99. data/lib/ruby_llm/providers/gemini/tools.rb +198 -0
  100. data/lib/ruby_llm/providers/gemini/transcription.rb +116 -0
  101. data/lib/ruby_llm/providers/gemini.rb +37 -0
  102. data/lib/ruby_llm/providers/gpustack/chat.rb +27 -0
  103. data/lib/ruby_llm/providers/gpustack/media.rb +46 -0
  104. data/lib/ruby_llm/providers/gpustack/models.rb +90 -0
  105. data/lib/ruby_llm/providers/gpustack.rb +34 -0
  106. data/lib/ruby_llm/providers/mistral/capabilities.rb +155 -0
  107. data/lib/ruby_llm/providers/mistral/chat.rb +24 -0
  108. data/lib/ruby_llm/providers/mistral/embeddings.rb +33 -0
  109. data/lib/ruby_llm/providers/mistral/models.rb +48 -0
  110. data/lib/ruby_llm/providers/mistral.rb +32 -0
  111. data/lib/ruby_llm/providers/ollama/chat.rb +27 -0
  112. data/lib/ruby_llm/providers/ollama/media.rb +46 -0
  113. data/lib/ruby_llm/providers/ollama/models.rb +36 -0
  114. data/lib/ruby_llm/providers/ollama.rb +30 -0
  115. data/lib/ruby_llm/providers/openai/capabilities.rb +299 -0
  116. data/lib/ruby_llm/providers/openai/chat.rb +88 -0
  117. data/lib/ruby_llm/providers/openai/embeddings.rb +33 -0
  118. data/lib/ruby_llm/providers/openai/images.rb +38 -0
  119. data/lib/ruby_llm/providers/openai/media.rb +81 -0
  120. data/lib/ruby_llm/providers/openai/models.rb +39 -0
  121. data/lib/ruby_llm/providers/openai/moderation.rb +34 -0
  122. data/lib/ruby_llm/providers/openai/streaming.rb +46 -0
  123. data/lib/ruby_llm/providers/openai/tools.rb +98 -0
  124. data/lib/ruby_llm/providers/openai/transcription.rb +70 -0
  125. data/lib/ruby_llm/providers/openai.rb +44 -0
  126. data/lib/ruby_llm/providers/openai_responses.rb +395 -0
  127. data/lib/ruby_llm/providers/openrouter/models.rb +73 -0
  128. data/lib/ruby_llm/providers/openrouter.rb +26 -0
  129. data/lib/ruby_llm/providers/perplexity/capabilities.rb +137 -0
  130. data/lib/ruby_llm/providers/perplexity/chat.rb +16 -0
  131. data/lib/ruby_llm/providers/perplexity/models.rb +42 -0
  132. data/lib/ruby_llm/providers/perplexity.rb +48 -0
  133. data/lib/ruby_llm/providers/vertexai/chat.rb +14 -0
  134. data/lib/ruby_llm/providers/vertexai/embeddings.rb +32 -0
  135. data/lib/ruby_llm/providers/vertexai/models.rb +130 -0
  136. data/lib/ruby_llm/providers/vertexai/streaming.rb +14 -0
  137. data/lib/ruby_llm/providers/vertexai/transcription.rb +16 -0
  138. data/lib/ruby_llm/providers/vertexai.rb +55 -0
  139. data/lib/ruby_llm/railtie.rb +35 -0
  140. data/lib/ruby_llm/responses_session.rb +77 -0
  141. data/lib/ruby_llm/stream_accumulator.rb +101 -0
  142. data/lib/ruby_llm/streaming.rb +153 -0
  143. data/lib/ruby_llm/tool.rb +209 -0
  144. data/lib/ruby_llm/tool_call.rb +22 -0
  145. data/lib/ruby_llm/tool_executors.rb +125 -0
  146. data/lib/ruby_llm/transcription.rb +35 -0
  147. data/lib/ruby_llm/utils.rb +91 -0
  148. data/lib/ruby_llm/version.rb +5 -0
  149. data/lib/ruby_llm.rb +140 -0
  150. data/lib/tasks/models.rake +525 -0
  151. data/lib/tasks/release.rake +67 -0
  152. data/lib/tasks/ruby_llm.rake +15 -0
  153. data/lib/tasks/vcr.rake +92 -0
  154. metadata +346 -0
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ # Provides utility functions for data manipulation within the RubyLLM library
5
+ module Utils
6
+ module_function
7
+
8
+ def hash_get(hash, key)
9
+ hash[key.to_sym] || hash[key.to_s]
10
+ end
11
+
12
+ def to_safe_array(item)
13
+ case item
14
+ when Array
15
+ item
16
+ when Hash
17
+ [item]
18
+ else
19
+ Array(item)
20
+ end
21
+ end
22
+
23
+ def to_time(value)
24
+ return unless value
25
+
26
+ value.is_a?(Time) ? value : Time.parse(value.to_s)
27
+ end
28
+
29
+ def to_date(value)
30
+ return unless value
31
+
32
+ value.is_a?(Date) ? value : Date.parse(value.to_s)
33
+ end
34
+
35
+ def deep_merge(original, overrides)
36
+ original.merge(overrides) do |_key, original_value, overrides_value|
37
+ if original_value.is_a?(Hash) && overrides_value.is_a?(Hash)
38
+ deep_merge(original_value, overrides_value)
39
+ else
40
+ overrides_value
41
+ end
42
+ end
43
+ end
44
+
45
+ def deep_dup(value)
46
+ case value
47
+ when Hash
48
+ value.each_with_object({}) do |(key, val), duped|
49
+ duped[deep_dup(key)] = deep_dup(val)
50
+ end
51
+ when Array
52
+ value.map { |item| deep_dup(item) }
53
+ else
54
+ begin
55
+ value.dup
56
+ rescue TypeError
57
+ value
58
+ end
59
+ end
60
+ end
61
+
62
+ def deep_stringify_keys(value)
63
+ case value
64
+ when Hash
65
+ value.each_with_object({}) do |(key, val), result|
66
+ result[key.to_s] = deep_stringify_keys(val)
67
+ end
68
+ when Array
69
+ value.map { |item| deep_stringify_keys(item) }
70
+ when Symbol
71
+ value.to_s
72
+ else
73
+ value
74
+ end
75
+ end
76
+
77
+ def deep_symbolize_keys(value)
78
+ case value
79
+ when Hash
80
+ value.each_with_object({}) do |(key, val), result|
81
+ symbolized_key = key.respond_to?(:to_sym) ? key.to_sym : key
82
+ result[symbolized_key] = deep_symbolize_keys(val)
83
+ end
84
+ when Array
85
+ value.map { |item| deep_symbolize_keys(item) }
86
+ else
87
+ value
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ VERSION = '1.9.1'
5
+ end
data/lib/ruby_llm.rb ADDED
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'event_stream_parser'
5
+ require 'faraday'
6
+ require 'faraday/multipart'
7
+ require 'faraday/retry'
8
+ require 'json'
9
+ require 'logger'
10
+ require 'marcel'
11
+ require 'securerandom'
12
+ require 'zeitwerk'
13
+ require 'async/http/faraday/default'
14
+
15
+ loader = Zeitwerk::Loader.for_gem
16
+ loader.inflector.inflect(
17
+ 'ruby_llm' => 'RubyLLM',
18
+ 'llm' => 'LLM',
19
+ 'openai' => 'OpenAI',
20
+ 'openai_responses' => 'OpenAIResponses',
21
+ 'api' => 'API',
22
+ 'deepseek' => 'DeepSeek',
23
+ 'perplexity' => 'Perplexity',
24
+ 'bedrock' => 'Bedrock',
25
+ 'openrouter' => 'OpenRouter',
26
+ 'gpustack' => 'GPUStack',
27
+ 'mistral' => 'Mistral',
28
+ 'vertexai' => 'VertexAI',
29
+ 'pdf' => 'PDF',
30
+ 'UI' => 'UI'
31
+ )
32
+ loader.ignore("#{__dir__}/tasks")
33
+ loader.ignore("#{__dir__}/generators")
34
+ loader.ignore("#{__dir__}/ruby_llm/railtie.rb")
35
+ loader.setup
36
+
37
+ # A delightful Ruby interface to modern AI language models.
38
+ module RubyLLM
39
+ class Error < StandardError; end
40
+
41
+ class << self
42
+ def context
43
+ context_config = config.dup
44
+ yield context_config if block_given?
45
+ Context.new(context_config)
46
+ end
47
+
48
+ def chat(...)
49
+ Chat.new(...)
50
+ end
51
+
52
+ def embed(...)
53
+ Embedding.embed(...)
54
+ end
55
+
56
+ def moderate(...)
57
+ Moderation.moderate(...)
58
+ end
59
+
60
+ def paint(...)
61
+ Image.paint(...)
62
+ end
63
+
64
+ def transcribe(...)
65
+ Transcription.transcribe(...)
66
+ end
67
+
68
+ def models
69
+ Models.instance
70
+ end
71
+
72
+ def providers
73
+ Provider.providers.values
74
+ end
75
+
76
+ def configure
77
+ yield config
78
+ end
79
+
80
+ def config
81
+ @config ||= Configuration.new
82
+ end
83
+
84
+ def logger
85
+ @logger ||= config.logger || Logger.new(
86
+ config.log_file,
87
+ progname: 'RubyLLM',
88
+ level: config.log_level
89
+ )
90
+ end
91
+
92
+ # Registry for tool execution strategies.
93
+ # Executors receive an array of tool_calls and a block to execute each one.
94
+ # They must return a hash mapping tool_call.id to result.
95
+ #
96
+ # @return [Hash{Symbol => Proc}] Map of executor names to implementations
97
+ def tool_executors
98
+ @tool_executors ||= {}
99
+ end
100
+
101
+ # Registers a new tool executor for concurrent execution.
102
+ #
103
+ # @param name [Symbol] Executor name (e.g., :async, :threads)
104
+ # @yield [tool_calls, max_concurrency:, &execute] Block that executes tools concurrently
105
+ # @yieldparam tool_calls [Array<ToolCall>] Tools to execute
106
+ # @yieldparam max_concurrency [Integer, nil] Maximum concurrent executions
107
+ # @yieldparam execute [Proc] Block to call for each tool
108
+ # @yieldreturn [Hash{String => Object}] Map of tool_call.id to result
109
+ #
110
+ # @example
111
+ # RubyLLM.register_tool_executor(:custom) do |tool_calls, max_concurrency:, &execute|
112
+ # results = {}
113
+ # tool_calls.each { |tc| results[tc.id] = execute.call(tc) }
114
+ # results
115
+ # end
116
+ def register_tool_executor(name, &block)
117
+ tool_executors[name] = block
118
+ end
119
+ end
120
+ end
121
+
122
+ RubyLLM::Provider.register :anthropic, RubyLLM::Providers::Anthropic
123
+ RubyLLM::Provider.register :bedrock, RubyLLM::Providers::Bedrock
124
+ RubyLLM::Provider.register :deepseek, RubyLLM::Providers::DeepSeek
125
+ RubyLLM::Provider.register :gemini, RubyLLM::Providers::Gemini
126
+ RubyLLM::Provider.register :gpustack, RubyLLM::Providers::GPUStack
127
+ RubyLLM::Provider.register :mistral, RubyLLM::Providers::Mistral
128
+ RubyLLM::Provider.register :ollama, RubyLLM::Providers::Ollama
129
+ RubyLLM::Provider.register :openai, RubyLLM::Providers::OpenAI
130
+ RubyLLM::Provider.register :openrouter, RubyLLM::Providers::OpenRouter
131
+ RubyLLM::Provider.register :perplexity, RubyLLM::Providers::Perplexity
132
+ RubyLLM::Provider.register :vertexai, RubyLLM::Providers::VertexAI
133
+
134
+ # Load built-in tool executors for concurrent execution
135
+ require_relative 'ruby_llm/tool_executors'
136
+
137
+ if defined?(Rails::Railtie)
138
+ require 'ruby_llm/railtie'
139
+ require 'ruby_llm/active_record/acts_as'
140
+ end