ruby_llm-agents 0.1.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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +898 -0
  4. data/app/channels/ruby_llm/agents/executions_channel.rb +23 -0
  5. data/app/controllers/ruby_llm/agents/agents_controller.rb +100 -0
  6. data/app/controllers/ruby_llm/agents/application_controller.rb +20 -0
  7. data/app/controllers/ruby_llm/agents/dashboard_controller.rb +34 -0
  8. data/app/controllers/ruby_llm/agents/executions_controller.rb +93 -0
  9. data/app/helpers/ruby_llm/agents/application_helper.rb +149 -0
  10. data/app/javascript/ruby_llm/agents/controllers/filter_controller.js +56 -0
  11. data/app/javascript/ruby_llm/agents/controllers/index.js +12 -0
  12. data/app/javascript/ruby_llm/agents/controllers/refresh_controller.js +83 -0
  13. data/app/models/ruby_llm/agents/execution/analytics.rb +166 -0
  14. data/app/models/ruby_llm/agents/execution/metrics.rb +89 -0
  15. data/app/models/ruby_llm/agents/execution/scopes.rb +81 -0
  16. data/app/models/ruby_llm/agents/execution.rb +81 -0
  17. data/app/services/ruby_llm/agents/agent_registry.rb +112 -0
  18. data/app/views/layouts/rubyllm/agents/application.html.erb +276 -0
  19. data/app/views/rubyllm/agents/agents/index.html.erb +89 -0
  20. data/app/views/rubyllm/agents/agents/show.html.erb +562 -0
  21. data/app/views/rubyllm/agents/dashboard/_execution_item.html.erb +48 -0
  22. data/app/views/rubyllm/agents/dashboard/index.html.erb +121 -0
  23. data/app/views/rubyllm/agents/executions/_execution.html.erb +64 -0
  24. data/app/views/rubyllm/agents/executions/_filters.html.erb +172 -0
  25. data/app/views/rubyllm/agents/executions/_list.html.erb +229 -0
  26. data/app/views/rubyllm/agents/executions/index.html.erb +83 -0
  27. data/app/views/rubyllm/agents/executions/index.turbo_stream.erb +4 -0
  28. data/app/views/rubyllm/agents/executions/show.html.erb +240 -0
  29. data/app/views/rubyllm/agents/shared/_executions_table.html.erb +193 -0
  30. data/app/views/rubyllm/agents/shared/_stat_card.html.erb +14 -0
  31. data/app/views/rubyllm/agents/shared/_status_badge.html.erb +65 -0
  32. data/app/views/rubyllm/agents/shared/_status_dot.html.erb +18 -0
  33. data/config/routes.rb +13 -0
  34. data/lib/generators/ruby_llm_agents/agent_generator.rb +79 -0
  35. data/lib/generators/ruby_llm_agents/install_generator.rb +89 -0
  36. data/lib/generators/ruby_llm_agents/templates/add_prompts_migration.rb.tt +12 -0
  37. data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +46 -0
  38. data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +22 -0
  39. data/lib/generators/ruby_llm_agents/templates/initializer.rb.tt +36 -0
  40. data/lib/generators/ruby_llm_agents/templates/migration.rb.tt +66 -0
  41. data/lib/generators/ruby_llm_agents/upgrade_generator.rb +59 -0
  42. data/lib/ruby_llm/agents/base.rb +271 -0
  43. data/lib/ruby_llm/agents/configuration.rb +36 -0
  44. data/lib/ruby_llm/agents/engine.rb +32 -0
  45. data/lib/ruby_llm/agents/execution_logger_job.rb +59 -0
  46. data/lib/ruby_llm/agents/inflections.rb +13 -0
  47. data/lib/ruby_llm/agents/instrumentation.rb +245 -0
  48. data/lib/ruby_llm/agents/version.rb +7 -0
  49. data/lib/ruby_llm/agents.rb +26 -0
  50. data/lib/ruby_llm-agents.rb +3 -0
  51. metadata +164 -0
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Agents
5
+ class Configuration
6
+ attr_accessor :default_model,
7
+ :default_temperature,
8
+ :default_timeout,
9
+ :async_logging,
10
+ :retention_period,
11
+ :anomaly_cost_threshold,
12
+ :anomaly_duration_threshold,
13
+ :dashboard_auth,
14
+ :dashboard_parent_controller
15
+
16
+ attr_writer :cache_store
17
+
18
+ def initialize
19
+ @default_model = "gemini-2.0-flash"
20
+ @default_temperature = 0.0
21
+ @default_timeout = 60
22
+ @cache_store = nil
23
+ @async_logging = true
24
+ @retention_period = 30.days
25
+ @anomaly_cost_threshold = 5.00
26
+ @anomaly_duration_threshold = 10_000
27
+ @dashboard_auth = ->(_controller) { true }
28
+ @dashboard_parent_controller = "ActionController::Base"
29
+ end
30
+
31
+ def cache_store
32
+ @cache_store || Rails.cache
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Agents
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace RubyLLM::Agents
7
+
8
+ # Use to_prepare to load classes after autoloading is set up
9
+ # This ensures app/models are available when referenced
10
+ config.to_prepare do
11
+ require_relative "execution_logger_job"
12
+ require_relative "instrumentation"
13
+ require_relative "base"
14
+ end
15
+
16
+ # Configure generators
17
+ config.generators do |g|
18
+ g.test_framework :rspec
19
+ g.fixture_replacement :factory_bot
20
+ g.factory_bot dir: "spec/factories"
21
+ end
22
+
23
+ # Add app/agents to autoload paths for host app (must be done before initialization)
24
+ initializer "ruby_llm_agents.autoload_agents", before: :set_autoload_paths do |app|
25
+ agents_path = app.root.join("app/agents")
26
+ if agents_path.exist?
27
+ Rails.autoloaders.main.push_dir(agents_path.to_s)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Agents
5
+ # Background job for logging agent executions to the database
6
+ #
7
+ # This job is called automatically after each agent execution to:
8
+ # - Create an Execution record with all execution data
9
+ # - Calculate costs based on token usage
10
+ # - Log anomalies (expensive, slow, or failed executions)
11
+ #
12
+ # Configuration:
13
+ # RubyLLM::Agents.configure do |config|
14
+ # config.anomaly_cost_threshold = 5.00 # Log if cost > $5
15
+ # config.anomaly_duration_threshold = 10_000 # Log if duration > 10s
16
+ # end
17
+ #
18
+ class ExecutionLoggerJob < ActiveJob::Base
19
+ queue_as :default
20
+
21
+ # Retry with polynomial backoff
22
+ retry_on StandardError, wait: :polynomially_longer, attempts: 3
23
+
24
+ def perform(execution_data)
25
+ execution = Execution.create!(execution_data)
26
+
27
+ # Calculate costs if token data is available
28
+ if execution.input_tokens && execution.output_tokens
29
+ execution.calculate_costs!
30
+ execution.save!
31
+ end
32
+
33
+ # Log if execution was anomalous
34
+ log_anomaly(execution) if anomaly?(execution)
35
+ end
36
+
37
+ private
38
+
39
+ def anomaly?(execution)
40
+ config = RubyLLM::Agents.configuration
41
+
42
+ (execution.total_cost && execution.total_cost > config.anomaly_cost_threshold) ||
43
+ (execution.duration_ms && execution.duration_ms > config.anomaly_duration_threshold) ||
44
+ execution.status_error?
45
+ end
46
+
47
+ def log_anomaly(execution)
48
+ Rails.logger.warn(
49
+ "[RubyLLM::Agents] Execution anomaly detected: " \
50
+ "agent=#{execution.agent_type} " \
51
+ "id=#{execution.id} " \
52
+ "cost=$#{execution.total_cost} " \
53
+ "duration_ms=#{execution.duration_ms} " \
54
+ "status=#{execution.status}"
55
+ )
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Configure acronym for Rails inflector (used in routes)
4
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
5
+ inflect.acronym "LLM"
6
+ end
7
+
8
+ # Configure Zeitwerk inflection when autoloaders are available
9
+ ActiveSupport.on_load(:before_configuration) do
10
+ Rails.autoloaders.each do |autoloader|
11
+ autoloader.inflector.inflect("ruby_llm" => "RubyLLM")
12
+ end
13
+ end
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Agents
5
+ # Instrumentation concern for tracking agent executions
6
+ #
7
+ # Provides execution timing, token tracking, cost calculation, and error handling.
8
+ # Logs all executions to the database via a background job.
9
+ #
10
+ # == Usage
11
+ #
12
+ # Included automatically in RubyLLM::Agents::Base
13
+ #
14
+ # == Customization
15
+ #
16
+ # Override `execution_metadata` in your agent to add custom data:
17
+ #
18
+ # def execution_metadata
19
+ # { query: query, user_id: Current.user&.id }
20
+ # end
21
+ #
22
+ module Instrumentation
23
+ extend ActiveSupport::Concern
24
+
25
+ included do
26
+ attr_accessor :execution_id
27
+ end
28
+
29
+ # Wrap agent execution with metrics tracking
30
+ # Creates execution record at start with 'running' status, updates on completion
31
+ def instrument_execution(&block)
32
+ started_at = Time.current
33
+ @last_response = nil
34
+
35
+ # Create execution record immediately with running status
36
+ execution = create_running_execution(started_at)
37
+ self.execution_id = execution&.id
38
+
39
+ begin
40
+ result = yield
41
+
42
+ # Update to success
43
+ complete_execution(
44
+ execution,
45
+ completed_at: Time.current,
46
+ status: "success",
47
+ response: @last_response
48
+ )
49
+
50
+ result
51
+ rescue Timeout::Error => e
52
+ complete_execution(
53
+ execution,
54
+ completed_at: Time.current,
55
+ status: "timeout",
56
+ error: e
57
+ )
58
+ raise
59
+ rescue => e
60
+ complete_execution(
61
+ execution,
62
+ completed_at: Time.current,
63
+ status: "error",
64
+ error: e
65
+ )
66
+ raise
67
+ end
68
+ end
69
+
70
+ # Store response for metrics extraction
71
+ def capture_response(response)
72
+ @last_response = response
73
+ response
74
+ end
75
+
76
+ private
77
+
78
+ # Create execution record with running status at start
79
+ def create_running_execution(started_at)
80
+ execution_data = {
81
+ agent_type: self.class.name,
82
+ agent_version: self.class.version,
83
+ model_id: model,
84
+ temperature: temperature,
85
+ started_at: started_at,
86
+ status: "running",
87
+ parameters: sanitized_parameters,
88
+ metadata: execution_metadata,
89
+ system_prompt: safe_system_prompt,
90
+ user_prompt: safe_user_prompt
91
+ }
92
+
93
+ RubyLLM::Agents::Execution.create!(execution_data)
94
+ rescue StandardError => e
95
+ # Log error but don't fail the execution
96
+ Rails.logger.error("[RubyLLM::Agents] Failed to create execution record: #{e.message}")
97
+ nil
98
+ end
99
+
100
+ # Update execution record on completion
101
+ def complete_execution(execution, completed_at:, status:, response: nil, error: nil)
102
+ return legacy_log_execution(completed_at: completed_at, status: status, response: response, error: error) unless execution
103
+
104
+ started_at = execution.started_at
105
+ duration_ms = ((completed_at - started_at) * 1000).round
106
+
107
+ update_data = {
108
+ completed_at: completed_at,
109
+ duration_ms: duration_ms,
110
+ status: status
111
+ }
112
+
113
+ # Add response data if available
114
+ if response.is_a?(RubyLLM::Message)
115
+ update_data.merge!(
116
+ input_tokens: response.input_tokens,
117
+ output_tokens: response.output_tokens,
118
+ cached_tokens: response.cached_tokens || 0,
119
+ cache_creation_tokens: response.cache_creation_tokens || 0,
120
+ model_id: response.model_id || model,
121
+ response: serialize_response(response)
122
+ )
123
+ end
124
+
125
+ # Add error data if failed
126
+ if error
127
+ update_data.merge!(
128
+ error_message: error.message,
129
+ error_class: error.class.name
130
+ )
131
+ end
132
+
133
+ execution.update!(update_data)
134
+
135
+ # Calculate costs if token data is available
136
+ if execution.input_tokens && execution.output_tokens
137
+ execution.calculate_costs!
138
+ execution.save!
139
+ end
140
+ rescue StandardError => e
141
+ Rails.logger.error("[RubyLLM::Agents] Failed to update execution record: #{e.message}")
142
+ end
143
+
144
+ # Fallback for when initial execution creation failed
145
+ def legacy_log_execution(completed_at:, status:, response: nil, error: nil)
146
+ execution_data = {
147
+ agent_type: self.class.name,
148
+ agent_version: self.class.version,
149
+ model_id: model,
150
+ temperature: temperature,
151
+ started_at: Time.current,
152
+ completed_at: completed_at,
153
+ duration_ms: 0,
154
+ status: status,
155
+ parameters: sanitized_parameters,
156
+ metadata: execution_metadata,
157
+ system_prompt: safe_system_prompt,
158
+ user_prompt: safe_user_prompt
159
+ }
160
+
161
+ if response.is_a?(RubyLLM::Message)
162
+ execution_data.merge!(
163
+ input_tokens: response.input_tokens,
164
+ output_tokens: response.output_tokens,
165
+ cached_tokens: response.cached_tokens || 0,
166
+ cache_creation_tokens: response.cache_creation_tokens || 0,
167
+ model_id: response.model_id || model,
168
+ response: serialize_response(response)
169
+ )
170
+ end
171
+
172
+ if error
173
+ execution_data.merge!(
174
+ error_message: error.message,
175
+ error_class: error.class.name
176
+ )
177
+ end
178
+
179
+ if RubyLLM::Agents.configuration.async_logging
180
+ RubyLLM::Agents::ExecutionLoggerJob.perform_later(execution_data)
181
+ else
182
+ RubyLLM::Agents::ExecutionLoggerJob.new.perform(execution_data)
183
+ end
184
+ end
185
+
186
+ # Sanitize parameters to remove sensitive data
187
+ def sanitized_parameters
188
+ params = @options.dup
189
+
190
+ # Remove sensitive keys
191
+ sensitive_keys = %i[password token api_key secret credential auth key]
192
+ sensitive_keys.each { |key| params.delete(key) }
193
+
194
+ # Convert ActiveRecord objects to IDs
195
+ params.transform_values do |value|
196
+ case value
197
+ when defined?(ActiveRecord::Base) && ActiveRecord::Base
198
+ { id: value.id, type: value.class.name }
199
+ when Array
200
+ if value.first.is_a?(ActiveRecord::Base)
201
+ { ids: value.first(10).map(&:id), type: value.first.class.name, count: value.size }
202
+ else
203
+ value.first(10)
204
+ end
205
+ else
206
+ value
207
+ end
208
+ end
209
+ end
210
+
211
+ # Serialize full RubyLLM::Message response to JSON
212
+ def serialize_response(response)
213
+ {
214
+ content: response.content,
215
+ model_id: response.model_id,
216
+ input_tokens: response.input_tokens,
217
+ output_tokens: response.output_tokens,
218
+ cached_tokens: response.cached_tokens,
219
+ cache_creation_tokens: response.cache_creation_tokens
220
+ }.compact
221
+ end
222
+
223
+ # Hook for subclasses to add custom metadata
224
+ def execution_metadata
225
+ {}
226
+ end
227
+
228
+ # Safely capture system prompt (may raise or return nil)
229
+ def safe_system_prompt
230
+ respond_to?(:system_prompt) ? system_prompt.to_s : nil
231
+ rescue StandardError => e
232
+ Rails.logger.warn("[RubyLLM::Agents] Could not capture system_prompt: #{e.message}")
233
+ nil
234
+ end
235
+
236
+ # Safely capture user prompt (may raise or return nil)
237
+ def safe_user_prompt
238
+ respond_to?(:user_prompt) ? user_prompt.to_s : nil
239
+ rescue StandardError => e
240
+ Rails.logger.warn("[RubyLLM::Agents] Could not capture user_prompt: #{e.message}")
241
+ nil
242
+ end
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Agents
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "agents/version"
4
+ require_relative "agents/configuration"
5
+ require_relative "agents/inflections" if defined?(Rails)
6
+ require_relative "agents/engine" if defined?(Rails::Engine)
7
+
8
+ module RubyLLM
9
+ module Agents
10
+ class Error < StandardError; end
11
+
12
+ class << self
13
+ def configuration
14
+ @configuration ||= Configuration.new
15
+ end
16
+
17
+ def configure
18
+ yield(configuration)
19
+ end
20
+
21
+ def reset_configuration!
22
+ @configuration = Configuration.new
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ruby_llm/agents"
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_llm-agents
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - adham90
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: ruby_llm
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '1.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '1.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: turbo-rails
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: stimulus-rails
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '1.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '1.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: chartkick
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '5.0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '5.0'
82
+ description: A Rails engine for creating, managing, and monitoring LLM-powered agents.
83
+ Includes a DSL for agent configuration, execution tracking, cost analytics, and
84
+ a mountable dashboard UI.
85
+ email:
86
+ - hi@adham.dev
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - LICENSE.txt
92
+ - README.md
93
+ - app/channels/ruby_llm/agents/executions_channel.rb
94
+ - app/controllers/ruby_llm/agents/agents_controller.rb
95
+ - app/controllers/ruby_llm/agents/application_controller.rb
96
+ - app/controllers/ruby_llm/agents/dashboard_controller.rb
97
+ - app/controllers/ruby_llm/agents/executions_controller.rb
98
+ - app/helpers/ruby_llm/agents/application_helper.rb
99
+ - app/javascript/ruby_llm/agents/controllers/filter_controller.js
100
+ - app/javascript/ruby_llm/agents/controllers/index.js
101
+ - app/javascript/ruby_llm/agents/controllers/refresh_controller.js
102
+ - app/models/ruby_llm/agents/execution.rb
103
+ - app/models/ruby_llm/agents/execution/analytics.rb
104
+ - app/models/ruby_llm/agents/execution/metrics.rb
105
+ - app/models/ruby_llm/agents/execution/scopes.rb
106
+ - app/services/ruby_llm/agents/agent_registry.rb
107
+ - app/views/layouts/rubyllm/agents/application.html.erb
108
+ - app/views/rubyllm/agents/agents/index.html.erb
109
+ - app/views/rubyllm/agents/agents/show.html.erb
110
+ - app/views/rubyllm/agents/dashboard/_execution_item.html.erb
111
+ - app/views/rubyllm/agents/dashboard/index.html.erb
112
+ - app/views/rubyllm/agents/executions/_execution.html.erb
113
+ - app/views/rubyllm/agents/executions/_filters.html.erb
114
+ - app/views/rubyllm/agents/executions/_list.html.erb
115
+ - app/views/rubyllm/agents/executions/index.html.erb
116
+ - app/views/rubyllm/agents/executions/index.turbo_stream.erb
117
+ - app/views/rubyllm/agents/executions/show.html.erb
118
+ - app/views/rubyllm/agents/shared/_executions_table.html.erb
119
+ - app/views/rubyllm/agents/shared/_stat_card.html.erb
120
+ - app/views/rubyllm/agents/shared/_status_badge.html.erb
121
+ - app/views/rubyllm/agents/shared/_status_dot.html.erb
122
+ - config/routes.rb
123
+ - lib/generators/ruby_llm_agents/agent_generator.rb
124
+ - lib/generators/ruby_llm_agents/install_generator.rb
125
+ - lib/generators/ruby_llm_agents/templates/add_prompts_migration.rb.tt
126
+ - lib/generators/ruby_llm_agents/templates/agent.rb.tt
127
+ - lib/generators/ruby_llm_agents/templates/application_agent.rb.tt
128
+ - lib/generators/ruby_llm_agents/templates/initializer.rb.tt
129
+ - lib/generators/ruby_llm_agents/templates/migration.rb.tt
130
+ - lib/generators/ruby_llm_agents/upgrade_generator.rb
131
+ - lib/ruby_llm-agents.rb
132
+ - lib/ruby_llm/agents.rb
133
+ - lib/ruby_llm/agents/base.rb
134
+ - lib/ruby_llm/agents/configuration.rb
135
+ - lib/ruby_llm/agents/engine.rb
136
+ - lib/ruby_llm/agents/execution_logger_job.rb
137
+ - lib/ruby_llm/agents/inflections.rb
138
+ - lib/ruby_llm/agents/instrumentation.rb
139
+ - lib/ruby_llm/agents/version.rb
140
+ homepage: https://github.com/adham90/ruby_llm-agents
141
+ licenses:
142
+ - MIT
143
+ metadata:
144
+ homepage_uri: https://github.com/adham90/ruby_llm-agents
145
+ source_code_uri: https://github.com/adham90/ruby_llm-agents
146
+ changelog_uri: https://github.com/adham90/ruby_llm-agents/blob/main/CHANGELOG.md
147
+ rdoc_options: []
148
+ require_paths:
149
+ - lib
150
+ required_ruby_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 3.1.0
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ requirements: []
161
+ rubygems_version: 3.6.9
162
+ specification_version: 4
163
+ summary: Agent framework for building LLM-powered agents with RubyLLM
164
+ test_files: []