ruby_llm-agents 0.2.4 → 0.3.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +413 -0
  3. data/app/channels/ruby_llm/agents/executions_channel.rb +24 -1
  4. data/app/controllers/concerns/ruby_llm/agents/filterable.rb +81 -0
  5. data/app/controllers/concerns/ruby_llm/agents/paginatable.rb +51 -0
  6. data/app/controllers/ruby_llm/agents/agents_controller.rb +228 -59
  7. data/app/controllers/ruby_llm/agents/dashboard_controller.rb +167 -12
  8. data/app/controllers/ruby_llm/agents/executions_controller.rb +189 -31
  9. data/app/controllers/ruby_llm/agents/settings_controller.rb +20 -0
  10. data/app/helpers/ruby_llm/agents/application_helper.rb +307 -7
  11. data/app/models/ruby_llm/agents/execution/analytics.rb +224 -20
  12. data/app/models/ruby_llm/agents/execution/metrics.rb +41 -25
  13. data/app/models/ruby_llm/agents/execution/scopes.rb +234 -14
  14. data/app/models/ruby_llm/agents/execution.rb +259 -16
  15. data/app/services/ruby_llm/agents/agent_registry.rb +49 -12
  16. data/app/views/layouts/rubyllm/agents/application.html.erb +351 -85
  17. data/app/views/rubyllm/agents/agents/_version_comparison.html.erb +186 -0
  18. data/app/views/rubyllm/agents/agents/show.html.erb +233 -10
  19. data/app/views/rubyllm/agents/dashboard/_action_center.html.erb +62 -0
  20. data/app/views/rubyllm/agents/dashboard/_alerts_feed.html.erb +62 -0
  21. data/app/views/rubyllm/agents/dashboard/_breaker_strip.html.erb +47 -0
  22. data/app/views/rubyllm/agents/dashboard/_budgets_bar.html.erb +165 -0
  23. data/app/views/rubyllm/agents/dashboard/_now_strip.html.erb +10 -0
  24. data/app/views/rubyllm/agents/dashboard/_now_strip_values.html.erb +71 -0
  25. data/app/views/rubyllm/agents/dashboard/index.html.erb +215 -109
  26. data/app/views/rubyllm/agents/executions/_filters.html.erb +152 -155
  27. data/app/views/rubyllm/agents/executions/_list.html.erb +103 -12
  28. data/app/views/rubyllm/agents/executions/dry_run.html.erb +149 -0
  29. data/app/views/rubyllm/agents/executions/index.html.erb +17 -72
  30. data/app/views/rubyllm/agents/executions/index.turbo_stream.erb +16 -2
  31. data/app/views/rubyllm/agents/executions/show.html.erb +693 -14
  32. data/app/views/rubyllm/agents/settings/show.html.erb +369 -0
  33. data/app/views/rubyllm/agents/shared/_filter_dropdown.html.erb +121 -0
  34. data/app/views/rubyllm/agents/shared/_select_dropdown.html.erb +85 -0
  35. data/config/routes.rb +7 -0
  36. data/lib/generators/ruby_llm_agents/templates/add_attempts_migration.rb.tt +27 -0
  37. data/lib/generators/ruby_llm_agents/templates/add_caching_migration.rb.tt +23 -0
  38. data/lib/generators/ruby_llm_agents/templates/add_finish_reason_migration.rb.tt +19 -0
  39. data/lib/generators/ruby_llm_agents/templates/add_routing_migration.rb.tt +19 -0
  40. data/lib/generators/ruby_llm_agents/templates/add_streaming_migration.rb.tt +8 -0
  41. data/lib/generators/ruby_llm_agents/templates/add_tracing_migration.rb.tt +34 -0
  42. data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +66 -4
  43. data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +53 -6
  44. data/lib/generators/ruby_llm_agents/templates/initializer.rb.tt +143 -8
  45. data/lib/generators/ruby_llm_agents/templates/migration.rb.tt +38 -1
  46. data/lib/generators/ruby_llm_agents/upgrade_generator.rb +78 -0
  47. data/lib/ruby_llm/agents/alert_manager.rb +207 -0
  48. data/lib/ruby_llm/agents/attempt_tracker.rb +295 -0
  49. data/lib/ruby_llm/agents/base.rb +597 -112
  50. data/lib/ruby_llm/agents/budget_tracker.rb +360 -0
  51. data/lib/ruby_llm/agents/circuit_breaker.rb +197 -0
  52. data/lib/ruby_llm/agents/configuration.rb +279 -1
  53. data/lib/ruby_llm/agents/engine.rb +58 -6
  54. data/lib/ruby_llm/agents/execution_logger_job.rb +17 -6
  55. data/lib/ruby_llm/agents/inflections.rb +13 -2
  56. data/lib/ruby_llm/agents/instrumentation.rb +538 -87
  57. data/lib/ruby_llm/agents/redactor.rb +130 -0
  58. data/lib/ruby_llm/agents/reliability.rb +185 -0
  59. data/lib/ruby_llm/agents/version.rb +3 -1
  60. data/lib/ruby_llm/agents.rb +52 -0
  61. metadata +41 -2
  62. data/app/controllers/ruby_llm/agents/application_controller.rb +0 -37
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Migration to add finish_reason column to executions
4
+ #
5
+ # This column tracks why the LLM stopped generating:
6
+ # - stop: Natural end of response
7
+ # - length: Hit max_tokens limit
8
+ # - content_filter: Blocked by safety filter
9
+ # - tool_calls: Model wants to call a tool
10
+ # - other: Unknown reason
11
+ #
12
+ # Note: streaming and time_to_first_token_ms are added by add_streaming migration
13
+ #
14
+ # Run with: rails db:migrate
15
+ class AddFinishReasonToRubyLLMAgentsExecutions < ActiveRecord::Migration<%= migration_version %>
16
+ def change
17
+ add_column :ruby_llm_agents_executions, :finish_reason, :string
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Migration to add routing and retry tracking columns to executions
4
+ #
5
+ # These columns help understand why fallbacks happen and which errors
6
+ # are retryable for reliability analysis.
7
+ #
8
+ # Run with: rails db:migrate
9
+ class AddRoutingToRubyLLMAgentsExecutions < ActiveRecord::Migration<%= migration_version %>
10
+ def change
11
+ # Fallback tracking - why did we switch models?
12
+ # Values: price_limit, quality_fail, rate_limit, timeout, safety, other
13
+ add_column :ruby_llm_agents_executions, :fallback_reason, :string
14
+
15
+ # Error classification
16
+ add_column :ruby_llm_agents_executions, :retryable, :boolean
17
+ add_column :ruby_llm_agents_executions, :rate_limited, :boolean
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddStreamingToRubyLLMAgentsExecutions < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ add_column :ruby_llm_agents_executions, :streaming, :boolean, default: false
6
+ add_column :ruby_llm_agents_executions, :time_to_first_token_ms, :integer
7
+ end
8
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Migration to add distributed tracing columns to executions
4
+ #
5
+ # These columns enable linking executions across services and debugging
6
+ # production issues by correlating agent calls with web requests.
7
+ #
8
+ # Run with: rails db:migrate
9
+ class AddTracingToRubyLLMAgentsExecutions < ActiveRecord::Migration<%= migration_version %>
10
+ def change
11
+ # Request correlation - links to the originating HTTP request
12
+ add_column :ruby_llm_agents_executions, :request_id, :string
13
+
14
+ # OpenTelemetry tracing - for distributed tracing
15
+ add_column :ruby_llm_agents_executions, :trace_id, :string
16
+ add_column :ruby_llm_agents_executions, :span_id, :string
17
+
18
+ # Execution hierarchy - for nested agent calls
19
+ add_column :ruby_llm_agents_executions, :parent_execution_id, :bigint
20
+ add_column :ruby_llm_agents_executions, :root_execution_id, :bigint
21
+
22
+ # Indexes for common lookups
23
+ add_index :ruby_llm_agents_executions, :request_id
24
+ add_index :ruby_llm_agents_executions, :trace_id
25
+ add_index :ruby_llm_agents_executions, :parent_execution_id
26
+ add_index :ruby_llm_agents_executions, :root_execution_id
27
+
28
+ # Foreign keys for execution hierarchy
29
+ add_foreign_key :ruby_llm_agents_executions, :ruby_llm_agents_executions,
30
+ column: :parent_execution_id, on_delete: :nullify
31
+ add_foreign_key :ruby_llm_agents_executions, :ruby_llm_agents_executions,
32
+ column: :root_execution_id, on_delete: :nullify
33
+ end
34
+ end
@@ -1,21 +1,63 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class <%= class_name %>Agent < ApplicationAgent
4
+ # ============================================
5
+ # Model Configuration
6
+ # ============================================
7
+
4
8
  model "<%= options[:model] %>"
5
9
  temperature <%= options[:temperature] %>
6
10
  version "1.0"
11
+ # timeout 30 # Per-request timeout in seconds (default: 60)
12
+
13
+ # ============================================
14
+ # Caching
15
+ # ============================================
16
+
7
17
  <% if options[:cache] -%>
8
18
  cache <%= options[:cache] %>
9
19
  <% else -%>
10
- # cache 1.hour # Uncomment to enable caching
20
+ # cache 1.hour # Enable response caching with TTL
11
21
  <% end -%>
12
22
 
23
+ # ============================================
24
+ # Reliability (Retries & Fallbacks)
25
+ # ============================================
26
+
27
+ # Automatic retries with exponential backoff
28
+ # - max: Number of retry attempts
29
+ # - backoff: :constant or :exponential
30
+ # - base: Base delay in seconds
31
+ # - max_delay: Maximum delay between retries
32
+ # - on: Additional error classes to retry on
33
+ # retries max: 2, backoff: :exponential, base: 0.4, max_delay: 3.0
34
+
35
+ # Fallback models (tried in order when primary model fails)
36
+ # fallback_models ["gpt-4o-mini", "claude-3-haiku"]
37
+
38
+ # Total timeout across all retry/fallback attempts
39
+ # total_timeout 30
40
+
41
+ # Circuit breaker (prevents repeated calls to failing models)
42
+ # - errors: Number of errors to trigger open state
43
+ # - within: Rolling window in seconds
44
+ # - cooldown: Time to wait before allowing requests again
45
+ # circuit_breaker errors: 5, within: 60, cooldown: 300
46
+
47
+ # ============================================
48
+ # Parameters
49
+ # ============================================
50
+
13
51
  <% parsed_params.each do |param| -%>
14
52
  param :<%= param.name %><%= ", required: true" if param.required? %><%= ", default: #{param.default.inspect}" if param.default && !param.required? %>
15
53
  <% end -%>
16
54
 
17
55
  private
18
56
 
57
+ # ============================================
58
+ # Prompts (required)
59
+ # ============================================
60
+
19
61
  def system_prompt
20
62
  <<~PROMPT
21
63
  You are a helpful assistant.
@@ -32,15 +74,35 @@ class <%= class_name %>Agent < ApplicationAgent
32
74
  <% end -%>
33
75
  end
34
76
 
35
- # Uncomment to use structured output with RubyLLM::Schema
77
+ # ============================================
78
+ # Optional Overrides
79
+ # ============================================
80
+
81
+ # Structured output schema (returns parsed hash instead of raw text)
36
82
  # def schema
37
83
  # @schema ||= RubyLLM::Schema.create do
38
84
  # string :result, description: "The result"
85
+ # integer :confidence, description: "Confidence score 1-100"
86
+ # array :tags, description: "Relevant tags" do
87
+ # string
88
+ # end
39
89
  # end
40
90
  # end
41
91
 
42
- # Uncomment to add custom metadata to execution logs
92
+ # Custom response processing (default: symbolize hash keys)
93
+ # def process_response(response)
94
+ # content = response.content
95
+ # # Transform or validate the response
96
+ # content
97
+ # end
98
+
99
+ # Custom metadata to include in execution logs
43
100
  # def execution_metadata
44
- # { custom_field: value }
101
+ # { custom_field: "value", request_id: params[:request_id] }
102
+ # end
103
+
104
+ # Custom cache key data (default: all params except skip_cache, dry_run)
105
+ # def cache_key_data
106
+ # { query: params[:query], locale: I18n.locale }
45
107
  # end
46
108
  end
@@ -2,7 +2,8 @@
2
2
 
3
3
  # ApplicationAgent - Base class for all agents in this application
4
4
  #
5
- # All agents should inherit from this class to share common configuration.
5
+ # All agents inherit from this class. Configure shared settings here
6
+ # that apply to all agents, or override them per-agent as needed.
6
7
  #
7
8
  # Example:
8
9
  # class MyAgent < ApplicationAgent
@@ -13,10 +14,56 @@
13
14
  # end
14
15
  # end
15
16
  #
17
+ # Usage:
18
+ # MyAgent.call(query: "hello")
19
+ # MyAgent.call(query: "hello", dry_run: true) # Debug mode
20
+ # MyAgent.call(query: "hello", skip_cache: true) # Bypass cache
21
+ #
16
22
  class ApplicationAgent < RubyLLM::Agents::Base
17
- # Shared configuration for all agents
18
- # Uncomment and modify as needed:
19
- #
20
- # model "gemini-2.0-flash"
21
- # temperature 0.0
23
+ # ============================================
24
+ # Shared Model Configuration
25
+ # ============================================
26
+ # These settings are inherited by all agents
27
+
28
+ # model "gemini-2.0-flash" # Default model for all agents
29
+ # temperature 0.0 # Default temperature (0.0 = deterministic)
30
+ # timeout 60 # Default timeout in seconds
31
+
32
+ # ============================================
33
+ # Shared Caching
34
+ # ============================================
35
+
36
+ # cache 1.hour # Enable caching for all agents (override per-agent if needed)
37
+
38
+ # ============================================
39
+ # Shared Reliability Settings
40
+ # ============================================
41
+ # Configure once here, all agents inherit these settings
42
+
43
+ # Automatic retries for all agents
44
+ # retries max: 2, backoff: :exponential, base: 0.4, max_delay: 3.0
45
+
46
+ # Shared fallback models
47
+ # fallback_models ["gpt-4o-mini", "claude-3-haiku"]
48
+
49
+ # Total timeout across retries/fallbacks
50
+ # total_timeout 30
51
+
52
+ # Circuit breaker (per agent-model pair)
53
+ # circuit_breaker errors: 5, within: 60, cooldown: 300
54
+
55
+ # ============================================
56
+ # Shared Helper Methods
57
+ # ============================================
58
+ # Define methods here that can be used by all agents
59
+
60
+ # Example: Common system prompt prefix
61
+ # def system_prompt_prefix
62
+ # "You are an AI assistant for #{Rails.application.class.module_parent_name}."
63
+ # end
64
+
65
+ # Example: Common metadata
66
+ # def execution_metadata
67
+ # { app_version: Rails.application.config.version }
68
+ # end
22
69
  end
@@ -5,37 +5,172 @@
5
5
  # For more information, see: https://github.com/adham90/ruby_llm-agents
6
6
 
7
7
  RubyLLM::Agents.configure do |config|
8
- # Default model for all agents (can be overridden per agent)
8
+ # ============================================
9
+ # Model Defaults
10
+ # ============================================
11
+
12
+ # Default LLM model for all agents (can be overridden per agent with `model "model-name"`)
9
13
  # config.default_model = "gemini-2.0-flash"
10
14
 
11
- # Default temperature (0.0 = deterministic, 1.0 = creative)
15
+ # Default temperature (0.0 = deterministic, 2.0 = creative)
12
16
  # config.default_temperature = 0.0
13
17
 
14
- # Default timeout in seconds
18
+ # Default timeout in seconds for each LLM request
15
19
  # config.default_timeout = 60
16
20
 
21
+ # Enable streaming by default for all agents
22
+ # When enabled, agents stream responses and track time-to-first-token
23
+ # config.default_streaming = false
24
+
25
+ # ============================================
26
+ # Caching
27
+ # ============================================
28
+
17
29
  # Cache store for agent response caching (defaults to Rails.cache)
18
30
  # config.cache_store = Rails.cache
31
+ # config.cache_store = ActiveSupport::Cache::MemoryStore.new
19
32
 
20
- # Async logging (set to false to log synchronously, useful for debugging)
33
+ # ============================================
34
+ # Execution Logging
35
+ # ============================================
36
+
37
+ # Async logging via background job (recommended for production)
38
+ # Set to false to log synchronously (useful for debugging)
21
39
  # config.async_logging = true
22
40
 
41
+ # Number of retry attempts for the async logging job on failure
42
+ # config.job_retry_attempts = 3
43
+
23
44
  # Retention period for execution records (used by cleanup tasks)
24
45
  # config.retention_period = 30.days
25
46
 
26
- # Anomaly detection thresholds (executions exceeding these are logged as warnings)
47
+ # ============================================
48
+ # Anomaly Detection
49
+ # ============================================
50
+
51
+ # Executions exceeding these thresholds are logged as warnings
27
52
  # config.anomaly_cost_threshold = 5.00 # dollars
28
53
  # config.anomaly_duration_threshold = 10_000 # milliseconds
29
54
 
30
- # HTTP Basic Auth (simple username/password protection)
55
+ # ============================================
56
+ # Dashboard Authentication
57
+ # ============================================
58
+
59
+ # Option 1: HTTP Basic Auth (simple username/password protection)
60
+ # Both username and password must be set to enable Basic Auth
31
61
  # config.basic_auth_username = "admin"
32
62
  # config.basic_auth_password = Rails.application.credentials.agents_password
33
63
 
34
- # Dashboard authentication (advanced - custom logic)
64
+ # Option 2: Custom authentication (advanced)
35
65
  # Return true to allow access, false to deny
36
- # Note: If basic_auth_username/password are set, they take precedence
66
+ # Note: If basic_auth is set, it takes precedence over dashboard_auth
37
67
  # config.dashboard_auth = ->(controller) { controller.current_user&.admin? }
38
68
 
39
69
  # Parent controller for dashboard (for authentication/layout inheritance)
40
70
  # config.dashboard_parent_controller = "ApplicationController"
71
+ # config.dashboard_parent_controller = "AdminController"
72
+
73
+ # ============================================
74
+ # Dashboard Display
75
+ # ============================================
76
+
77
+ # Number of records per page in dashboard listings
78
+ # config.per_page = 25
79
+
80
+ # Number of recent executions shown on the dashboard home
81
+ # config.recent_executions_limit = 10
82
+
83
+ # ============================================
84
+ # Reliability Defaults
85
+ # ============================================
86
+ # These defaults apply to all agents unless overridden per-agent
87
+
88
+ # Default retry configuration
89
+ # - max: Maximum retry attempts (0 = disabled)
90
+ # - backoff: Strategy (:constant or :exponential)
91
+ # - base: Base delay in seconds
92
+ # - max_delay: Maximum delay between retries
93
+ # - on: Additional error classes to retry on (extends defaults)
94
+ # config.default_retries = {
95
+ # max: 2,
96
+ # backoff: :exponential,
97
+ # base: 0.4,
98
+ # max_delay: 3.0,
99
+ # on: []
100
+ # }
101
+
102
+ # Default fallback models (tried in order when primary model fails)
103
+ # config.default_fallback_models = ["gpt-4o-mini", "claude-3-haiku"]
104
+
105
+ # Default total timeout across all retry/fallback attempts (nil = no limit)
106
+ # config.default_total_timeout = 30
107
+
108
+ # ============================================
109
+ # Governance - Budget Tracking
110
+ # ============================================
111
+
112
+ # Budget limits for cost governance
113
+ # - global_daily/global_monthly: Limits across all agents
114
+ # - per_agent_daily/per_agent_monthly: Per-agent limits (Hash of agent name => limit)
115
+ # - enforcement: :none (disabled), :soft (warn only), :hard (block requests)
116
+ # config.budgets = {
117
+ # global_daily: 25.0,
118
+ # global_monthly: 500.0,
119
+ # per_agent_daily: {
120
+ # "ContentGeneratorAgent" => 10.0,
121
+ # "SummaryAgent" => 5.0
122
+ # },
123
+ # per_agent_monthly: {
124
+ # "ContentGeneratorAgent" => 200.0
125
+ # },
126
+ # enforcement: :soft
127
+ # }
128
+
129
+ # ============================================
130
+ # Governance - Alerts
131
+ # ============================================
132
+
133
+ # Alert notifications for important events
134
+ # - slack_webhook_url: Slack incoming webhook URL
135
+ # - webhook_url: Generic webhook URL (receives JSON POST)
136
+ # - on_events: Events to trigger alerts
137
+ # - :budget_soft_cap - Soft budget limit reached
138
+ # - :budget_hard_cap - Hard budget limit exceeded
139
+ # - :breaker_open - Circuit breaker opened
140
+ # - :agent_anomaly - Cost/duration anomaly detected
141
+ # - custom: Lambda for custom handling
142
+ # config.alerts = {
143
+ # slack_webhook_url: ENV["SLACK_AGENTS_WEBHOOK"],
144
+ # webhook_url: ENV["AGENTS_ALERT_WEBHOOK"],
145
+ # on_events: [:budget_soft_cap, :budget_hard_cap, :breaker_open],
146
+ # custom: ->(event, payload) {
147
+ # Rails.logger.info("[AgentAlert] #{event}: #{payload}")
148
+ # }
149
+ # }
150
+
151
+ # ============================================
152
+ # Governance - Data Handling
153
+ # ============================================
154
+
155
+ # Whether to persist prompts in execution records
156
+ # Set to false to reduce storage or for privacy compliance
157
+ # config.persist_prompts = true
158
+
159
+ # Whether to persist LLM responses in execution records
160
+ # config.persist_responses = true
161
+
162
+ # Redaction configuration for PII and sensitive data
163
+ # - fields: Parameter names to redact (extends defaults: password, token, api_key, secret, etc.)
164
+ # - patterns: Regex patterns to match and redact in string values
165
+ # - placeholder: String to replace redacted values with
166
+ # - max_value_length: Truncate values longer than this (nil = no limit)
167
+ # config.redaction = {
168
+ # fields: %w[ssn credit_card phone_number email],
169
+ # patterns: [
170
+ # /\b\d{3}-\d{2}-\d{4}\b/, # SSN
171
+ # /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/ # Credit card
172
+ # ],
173
+ # placeholder: "[REDACTED]",
174
+ # max_value_length: 5000
175
+ # }
41
176
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class CreateRubyLlmAgentsExecutions < ActiveRecord::Migration<%= migration_version %>
3
+ class CreateRubyLLMAgentsExecutions < ActiveRecord::Migration<%= migration_version %>
4
4
  def change
5
5
  create_table :ruby_llm_agents_executions do |t|
6
6
  # Agent identification
@@ -17,6 +17,28 @@ class CreateRubyLlmAgentsExecutions < ActiveRecord::Migration<%= migration_versi
17
17
  t.datetime :completed_at
18
18
  t.integer :duration_ms
19
19
 
20
+ # Streaming and finish
21
+ t.boolean :streaming, default: false
22
+ t.integer :time_to_first_token_ms
23
+ t.string :finish_reason
24
+
25
+ # Distributed tracing
26
+ t.string :request_id
27
+ t.string :trace_id
28
+ t.string :span_id
29
+ t.bigint :parent_execution_id
30
+ t.bigint :root_execution_id
31
+
32
+ # Routing and retries
33
+ t.string :fallback_reason
34
+ t.boolean :retryable
35
+ t.boolean :rate_limited
36
+
37
+ # Caching
38
+ t.boolean :cache_hit, default: false
39
+ t.string :response_cache_key
40
+ t.datetime :cached_at
41
+
20
42
  # Status
21
43
  t.string :status, default: "success", null: false
22
44
 
@@ -58,6 +80,21 @@ class CreateRubyLlmAgentsExecutions < ActiveRecord::Migration<%= migration_versi
58
80
  add_index :ruby_llm_agents_executions, :duration_ms
59
81
  add_index :ruby_llm_agents_executions, :total_cost
60
82
 
83
+ # Tracing indexes
84
+ add_index :ruby_llm_agents_executions, :request_id
85
+ add_index :ruby_llm_agents_executions, :trace_id
86
+ add_index :ruby_llm_agents_executions, :parent_execution_id
87
+ add_index :ruby_llm_agents_executions, :root_execution_id
88
+
89
+ # Caching index
90
+ add_index :ruby_llm_agents_executions, :response_cache_key
91
+
92
+ # Foreign keys for execution hierarchy
93
+ add_foreign_key :ruby_llm_agents_executions, :ruby_llm_agents_executions,
94
+ column: :parent_execution_id, on_delete: :nullify
95
+ add_foreign_key :ruby_llm_agents_executions, :ruby_llm_agents_executions,
96
+ column: :root_execution_id, on_delete: :nullify
97
+
61
98
  # GIN indexes for JSONB columns (PostgreSQL only)
62
99
  # Uncomment if using PostgreSQL:
63
100
  # add_index :ruby_llm_agents_executions, :parameters, using: :gin
@@ -29,6 +29,84 @@ module RubyLlmAgents
29
29
  )
30
30
  end
31
31
 
32
+ def create_add_attempts_migration
33
+ # Check if columns already exist
34
+ if column_exists?(:ruby_llm_agents_executions, :attempts)
35
+ say_status :skip, "attempts column already exists", :yellow
36
+ return
37
+ end
38
+
39
+ migration_template(
40
+ "add_attempts_migration.rb.tt",
41
+ File.join(db_migrate_path, "add_attempts_to_ruby_llm_agents_executions.rb")
42
+ )
43
+ end
44
+
45
+ def create_add_streaming_migration
46
+ # Check if columns already exist
47
+ if column_exists?(:ruby_llm_agents_executions, :streaming)
48
+ say_status :skip, "streaming column already exists", :yellow
49
+ return
50
+ end
51
+
52
+ migration_template(
53
+ "add_streaming_migration.rb.tt",
54
+ File.join(db_migrate_path, "add_streaming_to_ruby_llm_agents_executions.rb")
55
+ )
56
+ end
57
+
58
+ def create_add_tracing_migration
59
+ # Check if columns already exist
60
+ if column_exists?(:ruby_llm_agents_executions, :trace_id)
61
+ say_status :skip, "trace_id column already exists", :yellow
62
+ return
63
+ end
64
+
65
+ migration_template(
66
+ "add_tracing_migration.rb.tt",
67
+ File.join(db_migrate_path, "add_tracing_to_ruby_llm_agents_executions.rb")
68
+ )
69
+ end
70
+
71
+ def create_add_routing_migration
72
+ # Check if columns already exist
73
+ if column_exists?(:ruby_llm_agents_executions, :fallback_reason)
74
+ say_status :skip, "fallback_reason column already exists", :yellow
75
+ return
76
+ end
77
+
78
+ migration_template(
79
+ "add_routing_migration.rb.tt",
80
+ File.join(db_migrate_path, "add_routing_to_ruby_llm_agents_executions.rb")
81
+ )
82
+ end
83
+
84
+ def create_add_finish_reason_migration
85
+ # Check if columns already exist
86
+ if column_exists?(:ruby_llm_agents_executions, :finish_reason)
87
+ say_status :skip, "finish_reason column already exists", :yellow
88
+ return
89
+ end
90
+
91
+ migration_template(
92
+ "add_finish_reason_migration.rb.tt",
93
+ File.join(db_migrate_path, "add_finish_reason_to_ruby_llm_agents_executions.rb")
94
+ )
95
+ end
96
+
97
+ def create_add_caching_migration
98
+ # Check if columns already exist
99
+ if column_exists?(:ruby_llm_agents_executions, :cache_hit)
100
+ say_status :skip, "cache_hit column already exists", :yellow
101
+ return
102
+ end
103
+
104
+ migration_template(
105
+ "add_caching_migration.rb.tt",
106
+ File.join(db_migrate_path, "add_caching_to_ruby_llm_agents_executions.rb")
107
+ )
108
+ end
109
+
32
110
  def show_post_upgrade_message
33
111
  say ""
34
112
  say "RubyLLM::Agents upgrade migration created!", :green