a2a-ruby 1.0.0

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 (128) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +137 -0
  4. data/.simplecov +46 -0
  5. data/.yardopts +10 -0
  6. data/CHANGELOG.md +33 -0
  7. data/CODE_OF_CONDUCT.md +128 -0
  8. data/CONTRIBUTING.md +165 -0
  9. data/Gemfile +43 -0
  10. data/Guardfile +34 -0
  11. data/LICENSE.txt +21 -0
  12. data/PUBLISHING_CHECKLIST.md +214 -0
  13. data/README.md +171 -0
  14. data/Rakefile +165 -0
  15. data/docs/agent_execution.md +309 -0
  16. data/docs/api_reference.md +792 -0
  17. data/docs/configuration.md +780 -0
  18. data/docs/events.md +475 -0
  19. data/docs/getting_started.md +668 -0
  20. data/docs/integration.md +262 -0
  21. data/docs/server_apps.md +621 -0
  22. data/docs/troubleshooting.md +765 -0
  23. data/lib/a2a/client/api_methods.rb +263 -0
  24. data/lib/a2a/client/auth/api_key.rb +161 -0
  25. data/lib/a2a/client/auth/interceptor.rb +288 -0
  26. data/lib/a2a/client/auth/jwt.rb +189 -0
  27. data/lib/a2a/client/auth/oauth2.rb +146 -0
  28. data/lib/a2a/client/auth.rb +137 -0
  29. data/lib/a2a/client/base.rb +316 -0
  30. data/lib/a2a/client/config.rb +210 -0
  31. data/lib/a2a/client/connection_pool.rb +233 -0
  32. data/lib/a2a/client/http_client.rb +524 -0
  33. data/lib/a2a/client/json_rpc_handler.rb +136 -0
  34. data/lib/a2a/client/middleware/circuit_breaker_interceptor.rb +245 -0
  35. data/lib/a2a/client/middleware/logging_interceptor.rb +371 -0
  36. data/lib/a2a/client/middleware/rate_limit_interceptor.rb +142 -0
  37. data/lib/a2a/client/middleware/retry_interceptor.rb +161 -0
  38. data/lib/a2a/client/middleware.rb +116 -0
  39. data/lib/a2a/client/performance_tracker.rb +60 -0
  40. data/lib/a2a/configuration/defaults.rb +34 -0
  41. data/lib/a2a/configuration/environment_loader.rb +76 -0
  42. data/lib/a2a/configuration/file_loader.rb +115 -0
  43. data/lib/a2a/configuration/inheritance.rb +101 -0
  44. data/lib/a2a/configuration/validator.rb +180 -0
  45. data/lib/a2a/configuration.rb +201 -0
  46. data/lib/a2a/errors.rb +291 -0
  47. data/lib/a2a/modules.rb +50 -0
  48. data/lib/a2a/monitoring/alerting.rb +490 -0
  49. data/lib/a2a/monitoring/distributed_tracing.rb +398 -0
  50. data/lib/a2a/monitoring/health_endpoints.rb +204 -0
  51. data/lib/a2a/monitoring/metrics_collector.rb +438 -0
  52. data/lib/a2a/monitoring.rb +463 -0
  53. data/lib/a2a/plugin.rb +358 -0
  54. data/lib/a2a/plugin_manager.rb +159 -0
  55. data/lib/a2a/plugins/example_auth.rb +81 -0
  56. data/lib/a2a/plugins/example_middleware.rb +118 -0
  57. data/lib/a2a/plugins/example_transport.rb +76 -0
  58. data/lib/a2a/protocol/agent_card.rb +8 -0
  59. data/lib/a2a/protocol/agent_card_server.rb +584 -0
  60. data/lib/a2a/protocol/capability.rb +496 -0
  61. data/lib/a2a/protocol/json_rpc.rb +254 -0
  62. data/lib/a2a/protocol/message.rb +8 -0
  63. data/lib/a2a/protocol/task.rb +8 -0
  64. data/lib/a2a/rails/a2a_controller.rb +258 -0
  65. data/lib/a2a/rails/controller_helpers.rb +499 -0
  66. data/lib/a2a/rails/engine.rb +167 -0
  67. data/lib/a2a/rails/generators/agent_generator.rb +311 -0
  68. data/lib/a2a/rails/generators/install_generator.rb +209 -0
  69. data/lib/a2a/rails/generators/migration_generator.rb +232 -0
  70. data/lib/a2a/rails/generators/templates/add_a2a_indexes.rb +57 -0
  71. data/lib/a2a/rails/generators/templates/agent_controller.rb +122 -0
  72. data/lib/a2a/rails/generators/templates/agent_controller_spec.rb +160 -0
  73. data/lib/a2a/rails/generators/templates/agent_readme.md +200 -0
  74. data/lib/a2a/rails/generators/templates/create_a2a_push_notification_configs.rb +68 -0
  75. data/lib/a2a/rails/generators/templates/create_a2a_tasks.rb +83 -0
  76. data/lib/a2a/rails/generators/templates/example_agent_controller.rb +228 -0
  77. data/lib/a2a/rails/generators/templates/initializer.rb +108 -0
  78. data/lib/a2a/rails/generators/templates/push_notification_config_model.rb +228 -0
  79. data/lib/a2a/rails/generators/templates/task_model.rb +200 -0
  80. data/lib/a2a/rails/tasks/a2a.rake +228 -0
  81. data/lib/a2a/server/a2a_methods.rb +520 -0
  82. data/lib/a2a/server/agent.rb +537 -0
  83. data/lib/a2a/server/agent_execution/agent_executor.rb +279 -0
  84. data/lib/a2a/server/agent_execution/request_context.rb +219 -0
  85. data/lib/a2a/server/apps/rack_app.rb +311 -0
  86. data/lib/a2a/server/apps/sinatra_app.rb +261 -0
  87. data/lib/a2a/server/default_request_handler.rb +350 -0
  88. data/lib/a2a/server/events/event_consumer.rb +116 -0
  89. data/lib/a2a/server/events/event_queue.rb +226 -0
  90. data/lib/a2a/server/example_agent.rb +248 -0
  91. data/lib/a2a/server/handler.rb +281 -0
  92. data/lib/a2a/server/middleware/authentication_middleware.rb +212 -0
  93. data/lib/a2a/server/middleware/cors_middleware.rb +171 -0
  94. data/lib/a2a/server/middleware/logging_middleware.rb +362 -0
  95. data/lib/a2a/server/middleware/rate_limit_middleware.rb +382 -0
  96. data/lib/a2a/server/middleware.rb +213 -0
  97. data/lib/a2a/server/push_notification_manager.rb +327 -0
  98. data/lib/a2a/server/request_handler.rb +136 -0
  99. data/lib/a2a/server/storage/base.rb +141 -0
  100. data/lib/a2a/server/storage/database.rb +266 -0
  101. data/lib/a2a/server/storage/memory.rb +274 -0
  102. data/lib/a2a/server/storage/redis.rb +320 -0
  103. data/lib/a2a/server/storage.rb +38 -0
  104. data/lib/a2a/server/task_manager.rb +534 -0
  105. data/lib/a2a/transport/grpc.rb +481 -0
  106. data/lib/a2a/transport/http.rb +415 -0
  107. data/lib/a2a/transport/sse.rb +499 -0
  108. data/lib/a2a/types/agent_card.rb +540 -0
  109. data/lib/a2a/types/artifact.rb +99 -0
  110. data/lib/a2a/types/base_model.rb +223 -0
  111. data/lib/a2a/types/events.rb +117 -0
  112. data/lib/a2a/types/message.rb +106 -0
  113. data/lib/a2a/types/part.rb +288 -0
  114. data/lib/a2a/types/push_notification.rb +139 -0
  115. data/lib/a2a/types/security.rb +167 -0
  116. data/lib/a2a/types/task.rb +154 -0
  117. data/lib/a2a/types.rb +88 -0
  118. data/lib/a2a/utils/helpers.rb +245 -0
  119. data/lib/a2a/utils/message_buffer.rb +278 -0
  120. data/lib/a2a/utils/performance.rb +247 -0
  121. data/lib/a2a/utils/rails_detection.rb +97 -0
  122. data/lib/a2a/utils/structured_logger.rb +306 -0
  123. data/lib/a2a/utils/time_helpers.rb +167 -0
  124. data/lib/a2a/utils/validation.rb +8 -0
  125. data/lib/a2a/version.rb +6 -0
  126. data/lib/a2a-rails.rb +58 -0
  127. data/lib/a2a.rb +198 -0
  128. metadata +437 -0
@@ -0,0 +1,311 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/named_base"
5
+
6
+ ##
7
+ # Rails generator for creating A2A agent controllers
8
+ #
9
+ # This generator creates a new controller with A2A agent functionality,
10
+ # including skills, capabilities, and method definitions.
11
+ #
12
+ # @example
13
+ # rails generate a2a:agent Chat
14
+ # rails generate a2a:agent Weather --skills=forecast,alerts
15
+ # rails generate a2a:agent Assistant --with-authentication --namespace=api/v1
16
+ #
17
+ module A2A
18
+ module Rails
19
+ module Generators
20
+ class AgentGenerator < Rails::Generators::NamedBase
21
+ source_root File.expand_path("templates", __dir__)
22
+
23
+ class_option :skills, type: :array, default: [],
24
+ desc: "List of skills to generate (e.g., --skills=chat,search)"
25
+
26
+ class_option :with_authentication, type: :boolean, default: false,
27
+ desc: "Generate authentication-protected methods"
28
+
29
+ class_option :namespace, type: :string, default: nil,
30
+ desc: "Namespace for the controller (e.g., api/v1)"
31
+
32
+ class_option :skip_tests, type: :boolean, default: false,
33
+ desc: "Skip generating test files"
34
+
35
+ class_option :api_only, type: :boolean, default: false,
36
+ desc: "Generate API-only controller (inherits from ActionController::API)"
37
+
38
+ desc "Generate an A2A agent controller"
39
+
40
+ def create_controller
41
+ template "agent_controller.rb", controller_file_path
42
+ say "Created A2A agent controller: #{controller_class_name}", :green
43
+ end
44
+
45
+ def create_tests
46
+ return if options[:skip_tests]
47
+
48
+ if rspec_available?
49
+ template "agent_controller_spec.rb", spec_file_path
50
+ say "Created RSpec test: #{spec_file_path}", :green
51
+ else
52
+ template "agent_controller_test.rb", test_file_path
53
+ say "Created test: #{test_file_path}", :green
54
+ end
55
+ end
56
+
57
+ def create_documentation
58
+ template "agent_readme.md", documentation_file_path
59
+ say "Created documentation: #{documentation_file_path}", :green
60
+ end
61
+
62
+ def add_routes
63
+ route_content = generate_route_content
64
+
65
+ return unless File.exist?("config/routes.rb")
66
+
67
+ inject_into_file "config/routes.rb", after: "Rails.application.routes.draw do\n" do
68
+ route_content
69
+ end
70
+ say "Added routes for #{controller_class_name}", :green
71
+ end
72
+
73
+ def show_post_generation_instructions
74
+ say "\n#{'=' * 60}", :green
75
+ say "A2A Agent '#{class_name}' generated successfully!", :green
76
+ say "=" * 60, :green
77
+
78
+ say "\nGenerated files:", :yellow
79
+ say " #{controller_file_path}"
80
+ say " #{documentation_file_path}"
81
+ say " #{test_file_path}" unless options[:skip_tests]
82
+
83
+ say "\nNext steps:", :yellow
84
+ say "1. Customize the agent skills and methods in #{controller_file_path}"
85
+ say "2. Implement the A2A method handlers"
86
+ say "3. Test your agent using the generated test file"
87
+
88
+ say "\nAgent endpoints:", :yellow
89
+ say " GET #{agent_card_path} (Agent Card)"
90
+ say " POST #{rpc_path} (JSON-RPC Methods)"
91
+
92
+ if skills.any?
93
+ say "\nGenerated skills:", :yellow
94
+ skills.each do |skill|
95
+ say " - #{skill.humanize}"
96
+ end
97
+ end
98
+
99
+ say "\nFor more information, visit: https://a2a-protocol.org/sdk/ruby/agents/", :blue
100
+ end
101
+
102
+ private
103
+
104
+ def controller_file_path
105
+ if namespace.present?
106
+ "app/controllers/#{namespace}/#{file_name}_controller.rb"
107
+ else
108
+ "app/controllers/#{file_name}_controller.rb"
109
+ end
110
+ end
111
+
112
+ def spec_file_path
113
+ if namespace.present?
114
+ "spec/controllers/#{namespace}/#{file_name}_controller_spec.rb"
115
+ else
116
+ "spec/controllers/#{file_name}_controller_spec.rb"
117
+ end
118
+ end
119
+
120
+ def test_file_path
121
+ if namespace.present?
122
+ "test/controllers/#{namespace}/#{file_name}_controller_test.rb"
123
+ else
124
+ "test/controllers/#{file_name}_controller_test.rb"
125
+ end
126
+ end
127
+
128
+ def documentation_file_path
129
+ if namespace.present?
130
+ "docs/agents/#{namespace}/#{file_name}.md"
131
+ else
132
+ "docs/agents/#{file_name}.md"
133
+ end
134
+ end
135
+
136
+ def controller_class_name
137
+ if namespace.present?
138
+ "#{namespace.camelize}::#{class_name}Controller"
139
+ else
140
+ "#{class_name}Controller"
141
+ end
142
+ end
143
+
144
+ def controller_parent_class
145
+ if options[:api_only]
146
+ "ActionController::API"
147
+ else
148
+ "ApplicationController"
149
+ end
150
+ end
151
+
152
+ def namespace
153
+ options[:namespace]
154
+ end
155
+
156
+ def skills
157
+ @skills ||= options[:skills].map(&:strip).reject(&:empty?)
158
+ end
159
+
160
+ def with_authentication?
161
+ options[:with_authentication]
162
+ end
163
+
164
+ def generate_route_content
165
+ if namespace.present?
166
+ namespace_parts = namespace.split("/")
167
+ indent = " " * namespace_parts.length
168
+
169
+ route_lines = []
170
+
171
+ # Build nested namespace structure
172
+ namespace_parts.each_with_index do |ns, index|
173
+ route_lines << ((" " * index) + "namespace :#{ns} do")
174
+ end
175
+
176
+ # Add the actual route
177
+ route_lines << "#{indent} resources :#{file_name.pluralize}, only: [] do"
178
+ route_lines << "#{indent} collection do"
179
+ route_lines << "#{indent} get :agent_card"
180
+ route_lines << "#{indent} post :rpc"
181
+ route_lines << "#{indent} end"
182
+ route_lines << "#{indent} end"
183
+
184
+ # Close namespace blocks
185
+ namespace_parts.length.times do |index|
186
+ route_lines << "#{' ' * (namespace_parts.length - index - 1)}end"
187
+ end
188
+
189
+ "\n#{route_lines.join("\n")}\n"
190
+ else
191
+ <<~RUBY
192
+
193
+ # #{class_name} A2A Agent routes
194
+ resources :#{file_name.pluralize}, only: [] do
195
+ collection do
196
+ get :agent_card
197
+ post :rpc
198
+ end
199
+ end
200
+
201
+ RUBY
202
+ end
203
+ end
204
+
205
+ def rspec_available?
206
+ File.exist?("spec/spec_helper.rb") || File.exist?("spec/rails_helper.rb")
207
+ end
208
+
209
+ def agent_card_path
210
+ if namespace.present?
211
+ "/#{namespace}/#{file_name.pluralize}/agent_card"
212
+ else
213
+ "/#{file_name.pluralize}/agent_card"
214
+ end
215
+ end
216
+
217
+ def rpc_path
218
+ if namespace.present?
219
+ "/#{namespace}/#{file_name.pluralize}/rpc"
220
+ else
221
+ "/#{file_name.pluralize}/rpc"
222
+ end
223
+ end
224
+
225
+ def authentication_methods
226
+ if with_authentication?
227
+ skills.map { |skill| "#{skill}_secure" }
228
+ else
229
+ []
230
+ end
231
+ end
232
+
233
+ def generate_skill_methods
234
+ skills.map do |skill|
235
+ method_name = skill.underscore
236
+
237
+ if with_authentication? && authentication_methods.include?("#{skill}_secure")
238
+ <<~RUBY
239
+ # #{skill.humanize} skill method (authenticated)
240
+ a2a_method "#{method_name}" do |params|
241
+ # TODO: Implement #{skill.humanize.downcase} functionality
242
+ {
243
+ skill: "#{skill}",
244
+ message: "#{skill.humanize} functionality not yet implemented",
245
+ params: params,
246
+ user: current_user_info
247
+ }
248
+ end
249
+ RUBY
250
+ else
251
+ <<~RUBY
252
+ # #{skill.humanize} skill method
253
+ a2a_method "#{method_name}" do |params|
254
+ # TODO: Implement #{skill.humanize.downcase} functionality
255
+ {
256
+ skill: "#{skill}",
257
+ message: "#{skill.humanize} functionality not yet implemented",
258
+ params: params
259
+ }
260
+ end
261
+ RUBY
262
+ end
263
+ end.join("\n\n")
264
+ end
265
+
266
+ def generate_skill_definitions
267
+ skills.map do |skill|
268
+ <<~RUBY
269
+ a2a_skill "#{skill}" do |skill|
270
+ skill.description = "#{skill.humanize} functionality"
271
+ skill.tags = ["#{skill}", "generated"]
272
+ skill.examples = [
273
+ {
274
+ input: { action: "#{skill}" },
275
+ output: { result: "#{skill} completed" }
276
+ }
277
+ ]
278
+ end
279
+ RUBY
280
+ end.join("\n\n")
281
+ end
282
+
283
+ def authentication_config
284
+ if with_authentication?
285
+ auth_methods = authentication_methods.map { |m| "\"#{m}\"" }.join(", ")
286
+ <<~RUBY
287
+
288
+ # Configure authentication for specific methods
289
+ a2a_authenticate :devise, methods: [#{auth_methods}]
290
+ RUBY
291
+ else
292
+ ""
293
+ end
294
+ end
295
+
296
+ def agent_description
297
+ if skills.any?
298
+ "A2A agent that provides #{skills.map(&:humanize).join(', ')} functionality"
299
+ else
300
+ "A2A agent for #{class_name.humanize.downcase} operations"
301
+ end
302
+ end
303
+
304
+ def agent_tags
305
+ base_tags = [class_name.underscore, "generated"]
306
+ (base_tags + skills).uniq
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/base"
5
+
6
+ ##
7
+ # Rails generator for installing A2A integration
8
+ #
9
+ # This generator sets up the basic A2A configuration and files needed
10
+ # for Rails integration.
11
+ #
12
+ # @example
13
+ # rails generate a2a:install
14
+ # rails generate a2a:install --with-authentication
15
+ # rails generate a2a:install --storage=redis
16
+ #
17
+ module A2A
18
+ module Rails
19
+ module Generators
20
+ class InstallGenerator < Rails::Generators::Base
21
+ source_root File.expand_path("templates", __dir__)
22
+
23
+ class_option :with_authentication, type: :boolean, default: false,
24
+ desc: "Generate authentication configuration"
25
+
26
+ class_option :storage, type: :string, default: "memory",
27
+ desc: "Storage backend (memory, database, redis)"
28
+
29
+ class_option :mount_path, type: :string, default: "/a2a",
30
+ desc: "Mount path for A2A endpoints"
31
+
32
+ class_option :skip_routes, type: :boolean, default: false,
33
+ desc: "Skip adding A2A routes"
34
+
35
+ class_option :skip_initializer, type: :boolean, default: false,
36
+ desc: "Skip creating initializer file"
37
+
38
+ desc "Install A2A Rails integration"
39
+
40
+ def create_initializer
41
+ return if options[:skip_initializer]
42
+
43
+ template "initializer.rb", "config/initializers/a2a.rb"
44
+ say "Created A2A initializer", :green
45
+ end
46
+
47
+ def add_routes
48
+ return if options[:skip_routes]
49
+
50
+ route_content = generate_route_content
51
+
52
+ if File.exist?("config/routes.rb")
53
+ inject_into_file "config/routes.rb", after: "Rails.application.routes.draw do\n" do
54
+ route_content
55
+ end
56
+ say "Added A2A routes", :green
57
+ else
58
+ say "Could not find config/routes.rb", :red
59
+ end
60
+ end
61
+
62
+ def create_application_controller_example
63
+ return unless options[:with_authentication]
64
+
65
+ template "application_controller_with_auth.rb",
66
+ "app/controllers/concerns/a2a_authentication.rb"
67
+ say "Created A2A authentication concern", :green
68
+ end
69
+
70
+ def create_example_agent
71
+ template "example_agent_controller.rb",
72
+ "app/controllers/example_agent_controller.rb"
73
+ say "Created example A2A agent controller", :green
74
+ end
75
+
76
+ def create_storage_configuration
77
+ case options[:storage]
78
+ when "database"
79
+ create_database_storage
80
+ when "redis"
81
+ create_redis_storage
82
+ else
83
+ # Memory storage is default, no additional setup needed
84
+ say "Using in-memory storage (default)", :yellow
85
+ end
86
+ end
87
+
88
+ def add_gem_dependencies
89
+ gem_content = []
90
+
91
+ case options[:storage]
92
+ when "database"
93
+ gem_content << "# A2A database storage dependencies"
94
+ gem_content << "gem 'activerecord', '>= 6.0'"
95
+ when "redis"
96
+ gem_content << "# A2A Redis storage dependencies"
97
+ gem_content << "gem 'redis', '~> 5.0'"
98
+ gem_content << "gem 'connection_pool', '~> 2.4'"
99
+ end
100
+
101
+ if options[:with_authentication]
102
+ gem_content << "# A2A authentication dependencies"
103
+ gem_content << "gem 'jwt', '~> 2.0'"
104
+ end
105
+
106
+ return unless gem_content.any?
107
+
108
+ append_to_file "Gemfile" do
109
+ "\n# A2A Ruby SDK dependencies\n#{gem_content.join("\n")}\n"
110
+ end
111
+ say "Added gem dependencies to Gemfile", :green
112
+ say "Run 'bundle install' to install new dependencies", :yellow
113
+ end
114
+
115
+ def show_post_install_instructions
116
+ say "\n#{'=' * 60}", :green
117
+ say "A2A Rails integration installed successfully!", :green
118
+ say "=" * 60, :green
119
+
120
+ say "\nNext steps:", :yellow
121
+ say "1. Run 'bundle install' if new gems were added"
122
+ say "2. Review and customize config/initializers/a2a.rb"
123
+ say "3. Check the example agent at app/controllers/example_agent_controller.rb"
124
+
125
+ if options[:storage] == "database"
126
+ say "4. Run 'rails generate a2a:migration' to create database tables"
127
+ say "5. Run 'rails db:migrate' to apply migrations"
128
+ end
129
+
130
+ say "\nA2A endpoints will be available at:", :yellow
131
+ say " #{options[:mount_path]}/rpc (JSON-RPC)"
132
+ say " #{options[:mount_path]}/agent-card (Agent Card)"
133
+ say " #{options[:mount_path]}/health (Health Check)"
134
+
135
+ say "\nFor more information, visit: https://a2a-protocol.org/sdk/ruby/", :blue
136
+ end
137
+
138
+ private
139
+
140
+ def generate_route_content
141
+ mount_path = options[:mount_path]
142
+
143
+ <<~RUBY
144
+
145
+ # A2A Protocol endpoints
146
+ mount A2A::Rails::Engine => "#{mount_path}"
147
+
148
+ RUBY
149
+ end
150
+
151
+ def create_database_storage
152
+ template "migration.rb",
153
+ "db/migrate/#{migration_timestamp}_create_a2a_tables.rb"
154
+ say "Created A2A database migration", :green
155
+ end
156
+
157
+ def create_redis_storage
158
+ template "redis_config.yml", "config/redis.yml"
159
+ say "Created Redis configuration", :green
160
+ end
161
+
162
+ def migration_timestamp
163
+ Time.now.strftime("%Y%m%d%H%M%S")
164
+ end
165
+
166
+ def authentication_strategy
167
+ if options[:with_authentication]
168
+ # Try to detect existing authentication gems
169
+ if gem_exists?("devise")
170
+ "devise"
171
+ elsif gem_exists?("jwt")
172
+ "jwt"
173
+ else
174
+ "api_key"
175
+ end
176
+ else
177
+ "none"
178
+ end
179
+ end
180
+
181
+ def gem_exists?(gem_name)
182
+ File.read("Gemfile").include?(gem_name) if File.exist?("Gemfile")
183
+ rescue StandardError
184
+ false
185
+ end
186
+
187
+ def storage_backend
188
+ options[:storage]
189
+ end
190
+
191
+ def mount_path
192
+ options[:mount_path]
193
+ end
194
+
195
+ def with_authentication?
196
+ options[:with_authentication]
197
+ end
198
+
199
+ def rails_version
200
+ ::Rails.version
201
+ end
202
+
203
+ def a2a_version
204
+ A2A::VERSION
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end