ruby_llm-agents 3.0.0 → 3.2.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.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/app/controllers/ruby_llm/agents/agents_controller.rb +16 -14
- data/app/controllers/ruby_llm/agents/dashboard_controller.rb +20 -20
- data/app/controllers/ruby_llm/agents/executions_controller.rb +5 -7
- data/app/helpers/ruby_llm/agents/application_helper.rb +57 -58
- data/app/models/ruby_llm/agents/execution/analytics.rb +27 -27
- data/app/models/ruby_llm/agents/execution/scopes.rb +4 -6
- data/app/models/ruby_llm/agents/execution.rb +26 -26
- data/app/models/ruby_llm/agents/tenant/budgetable.rb +16 -10
- data/app/models/ruby_llm/agents/tenant/resettable.rb +12 -12
- data/app/models/ruby_llm/agents/tenant/trackable.rb +7 -7
- data/app/services/ruby_llm/agents/agent_registry.rb +6 -6
- data/app/views/layouts/ruby_llm/agents/application.html.erb +142 -11
- data/app/views/ruby_llm/agents/agents/show.html.erb +10 -10
- data/app/views/ruby_llm/agents/dashboard/index.html.erb +10 -10
- data/app/views/ruby_llm/agents/executions/show.html.erb +13 -0
- data/lib/generators/ruby_llm_agents/agent_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/background_remover_generator.rb +6 -6
- data/lib/generators/ruby_llm_agents/embedder_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/image_analyzer_generator.rb +7 -7
- data/lib/generators/ruby_llm_agents/image_editor_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/image_generator_generator.rb +6 -6
- data/lib/generators/ruby_llm_agents/image_pipeline_generator.rb +9 -9
- data/lib/generators/ruby_llm_agents/image_transformer_generator.rb +6 -6
- data/lib/generators/ruby_llm_agents/image_upscaler_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/image_variator_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/install_generator.rb +3 -3
- data/lib/generators/ruby_llm_agents/migrate_structure_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/multi_tenancy_generator.rb +2 -2
- data/lib/generators/ruby_llm_agents/restructure_generator.rb +13 -13
- data/lib/generators/ruby_llm_agents/speaker_generator.rb +6 -6
- data/lib/generators/ruby_llm_agents/templates/add_assistant_prompt_migration.rb.tt +9 -0
- data/lib/generators/ruby_llm_agents/templates/split_execution_details_migration.rb.tt +2 -1
- data/lib/generators/ruby_llm_agents/transcriber_generator.rb +4 -4
- data/lib/generators/ruby_llm_agents/upgrade_generator.rb +22 -3
- data/lib/ruby_llm/agents/audio/speaker.rb +40 -31
- data/lib/ruby_llm/agents/audio/speech_client.rb +328 -0
- data/lib/ruby_llm/agents/audio/speech_pricing.rb +273 -0
- data/lib/ruby_llm/agents/audio/transcriber.rb +33 -33
- data/lib/ruby_llm/agents/base_agent.rb +16 -15
- data/lib/ruby_llm/agents/core/base/callbacks.rb +3 -3
- data/lib/ruby_llm/agents/core/configuration.rb +86 -73
- data/lib/ruby_llm/agents/core/errors.rb +27 -2
- data/lib/ruby_llm/agents/core/instrumentation.rb +101 -65
- data/lib/ruby_llm/agents/core/llm_tenant.rb +7 -7
- data/lib/ruby_llm/agents/core/version.rb +1 -1
- data/lib/ruby_llm/agents/dsl/base.rb +3 -3
- data/lib/ruby_llm/agents/dsl/reliability.rb +9 -9
- data/lib/ruby_llm/agents/image/analyzer/dsl.rb +1 -1
- data/lib/ruby_llm/agents/image/analyzer/execution.rb +4 -4
- data/lib/ruby_llm/agents/image/background_remover/dsl.rb +1 -1
- data/lib/ruby_llm/agents/image/background_remover/execution.rb +3 -3
- data/lib/ruby_llm/agents/image/concerns/image_operation_execution.rb +8 -8
- data/lib/ruby_llm/agents/image/editor/execution.rb +1 -1
- data/lib/ruby_llm/agents/image/generator/pricing.rb +9 -10
- data/lib/ruby_llm/agents/image/generator.rb +6 -6
- data/lib/ruby_llm/agents/image/pipeline/dsl.rb +6 -6
- data/lib/ruby_llm/agents/image/pipeline/execution.rb +9 -9
- data/lib/ruby_llm/agents/image/pipeline.rb +1 -1
- data/lib/ruby_llm/agents/image/transformer/execution.rb +1 -1
- data/lib/ruby_llm/agents/image/upscaler/dsl.rb +1 -1
- data/lib/ruby_llm/agents/image/upscaler/execution.rb +3 -5
- data/lib/ruby_llm/agents/image/variator/execution.rb +1 -1
- data/lib/ruby_llm/agents/infrastructure/alert_manager.rb +4 -4
- data/lib/ruby_llm/agents/infrastructure/attempt_tracker.rb +4 -4
- data/lib/ruby_llm/agents/infrastructure/budget/budget_query.rb +9 -9
- data/lib/ruby_llm/agents/infrastructure/budget/config_resolver.rb +3 -3
- data/lib/ruby_llm/agents/infrastructure/budget/forecaster.rb +1 -1
- data/lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb +17 -17
- data/lib/ruby_llm/agents/infrastructure/circuit_breaker.rb +1 -0
- data/lib/ruby_llm/agents/infrastructure/execution_logger_job.rb +1 -1
- data/lib/ruby_llm/agents/infrastructure/reliability.rb +6 -6
- data/lib/ruby_llm/agents/pipeline/builder.rb +11 -11
- data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +3 -3
- data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +4 -4
- data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +62 -21
- data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +2 -3
- data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +82 -4
- data/lib/ruby_llm/agents/results/background_removal_result.rb +6 -6
- data/lib/ruby_llm/agents/results/embedding_result.rb +15 -15
- data/lib/ruby_llm/agents/results/image_analysis_result.rb +7 -7
- data/lib/ruby_llm/agents/results/image_edit_result.rb +4 -4
- data/lib/ruby_llm/agents/results/image_generation_result.rb +5 -5
- data/lib/ruby_llm/agents/results/image_pipeline_result.rb +4 -4
- data/lib/ruby_llm/agents/results/image_transform_result.rb +4 -4
- data/lib/ruby_llm/agents/results/image_upscale_result.rb +5 -5
- data/lib/ruby_llm/agents/results/image_variation_result.rb +4 -4
- data/lib/ruby_llm/agents/results/transcription_result.rb +1 -1
- data/lib/ruby_llm/agents/text/embedder.rb +13 -13
- metadata +4 -1
|
@@ -67,27 +67,27 @@ module RubyLLM
|
|
|
67
67
|
belongs_to :parent_execution, class_name: "RubyLLM::Agents::Execution", optional: true
|
|
68
68
|
belongs_to :root_execution, class_name: "RubyLLM::Agents::Execution", optional: true
|
|
69
69
|
has_many :child_executions, class_name: "RubyLLM::Agents::Execution",
|
|
70
|
-
|
|
70
|
+
foreign_key: :parent_execution_id, dependent: :nullify, inverse_of: :parent_execution
|
|
71
71
|
|
|
72
72
|
# Detail record for large payloads (prompts, responses, tool calls, etc.)
|
|
73
73
|
has_one :detail, class_name: "RubyLLM::Agents::ExecutionDetail",
|
|
74
|
-
|
|
74
|
+
foreign_key: :execution_id, dependent: :destroy
|
|
75
75
|
|
|
76
76
|
# Delegations so existing code keeps working transparently
|
|
77
|
-
delegate :system_prompt, :user_prompt, :response, :error_message,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
delegate :system_prompt, :user_prompt, :assistant_prompt, :response, :error_message,
|
|
78
|
+
:messages_summary, :tool_calls, :attempts, :fallback_chain,
|
|
79
|
+
:parameters, :routed_to, :classification_result,
|
|
80
|
+
:cached_at, :cache_creation_tokens,
|
|
81
|
+
to: :detail, prefix: false, allow_nil: true
|
|
82
82
|
|
|
83
83
|
# Validations
|
|
84
84
|
validates :agent_type, :model_id, :started_at, presence: true
|
|
85
|
-
validates :status, inclusion: {
|
|
86
|
-
validates :temperature, numericality: {
|
|
87
|
-
validates :input_tokens, :output_tokens, numericality: {
|
|
88
|
-
validates :duration_ms, numericality: {
|
|
89
|
-
validates :input_cost, :output_cost, :total_cost, numericality: {
|
|
90
|
-
validates :finish_reason, inclusion: {
|
|
85
|
+
validates :status, inclusion: {in: statuses.keys}
|
|
86
|
+
validates :temperature, numericality: {greater_than_or_equal_to: 0, less_than_or_equal_to: 2}, allow_nil: true
|
|
87
|
+
validates :input_tokens, :output_tokens, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
|
|
88
|
+
validates :duration_ms, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
|
|
89
|
+
validates :input_cost, :output_cost, :total_cost, numericality: {greater_than_or_equal_to: 0}, allow_nil: true
|
|
90
|
+
validates :finish_reason, inclusion: {in: FINISH_REASONS}, allow_nil: true
|
|
91
91
|
|
|
92
92
|
before_save :calculate_total_tokens, if: -> { input_tokens_changed? || output_tokens_changed? }
|
|
93
93
|
before_save :calculate_total_cost, if: -> { input_cost_changed? || output_cost_changed? }
|
|
@@ -130,10 +130,10 @@ module RubyLLM
|
|
|
130
130
|
# @return [Boolean] true if more than one attempt was made
|
|
131
131
|
def has_retries?
|
|
132
132
|
count = if self.class.column_names.include?("attempts_count")
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
attempts_count
|
|
134
|
+
elsif self.class.column_names.include?("attempts")
|
|
135
|
+
attempts&.size
|
|
136
|
+
end
|
|
137
137
|
(count || 0) > 1
|
|
138
138
|
end
|
|
139
139
|
|
|
@@ -278,16 +278,16 @@ module RubyLLM
|
|
|
278
278
|
# @return [Hash] Now strip metrics with period-over-period comparisons
|
|
279
279
|
def self.now_strip_data(range: "today")
|
|
280
280
|
current_scope = case range
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
281
|
+
when "7d" then last_n_days(7)
|
|
282
|
+
when "30d" then last_n_days(30)
|
|
283
|
+
else today
|
|
284
|
+
end
|
|
285
285
|
|
|
286
286
|
previous_scope = case range
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
287
|
+
when "7d" then where(created_at: 14.days.ago.beginning_of_day..7.days.ago.beginning_of_day)
|
|
288
|
+
when "30d" then where(created_at: 60.days.ago.beginning_of_day..30.days.ago.beginning_of_day)
|
|
289
|
+
else yesterday
|
|
290
|
+
end
|
|
291
291
|
|
|
292
292
|
current = {
|
|
293
293
|
running: running.count,
|
|
@@ -371,7 +371,7 @@ module RubyLLM
|
|
|
371
371
|
return nil unless lookup_model_id
|
|
372
372
|
|
|
373
373
|
RubyLLM::Models.find(lookup_model_id)
|
|
374
|
-
rescue
|
|
374
|
+
rescue
|
|
375
375
|
nil
|
|
376
376
|
end
|
|
377
377
|
end
|
|
@@ -35,13 +35,13 @@ module RubyLLM
|
|
|
35
35
|
|
|
36
36
|
included do
|
|
37
37
|
# Validations
|
|
38
|
-
validates :enforcement, inclusion: {
|
|
38
|
+
validates :enforcement, inclusion: {in: ENFORCEMENT_MODES}, allow_nil: true
|
|
39
39
|
validates :daily_limit, :monthly_limit,
|
|
40
|
-
|
|
40
|
+
numericality: {greater_than_or_equal_to: 0}, allow_nil: true
|
|
41
41
|
validates :daily_token_limit, :monthly_token_limit,
|
|
42
|
-
|
|
42
|
+
numericality: {greater_than_or_equal_to: 0, only_integer: true}, allow_nil: true
|
|
43
43
|
validates :daily_execution_limit, :monthly_execution_limit,
|
|
44
|
-
|
|
44
|
+
numericality: {greater_than_or_equal_to: 0, only_integer: true}, allow_nil: true
|
|
45
45
|
|
|
46
46
|
# Scopes
|
|
47
47
|
scope :with_budgets, -> { where.not(daily_limit: nil).or(where.not(monthly_limit: nil)) }
|
|
@@ -203,17 +203,23 @@ module RubyLLM
|
|
|
203
203
|
def remaining_budget(type: :daily_cost)
|
|
204
204
|
case type
|
|
205
205
|
when :daily_cost
|
|
206
|
-
effective_daily_limit && (ensure_daily_reset
|
|
206
|
+
effective_daily_limit && (ensure_daily_reset!
|
|
207
|
+
effective_daily_limit - daily_cost_spent)
|
|
207
208
|
when :monthly_cost
|
|
208
|
-
effective_monthly_limit && (ensure_monthly_reset
|
|
209
|
+
effective_monthly_limit && (ensure_monthly_reset!
|
|
210
|
+
effective_monthly_limit - monthly_cost_spent)
|
|
209
211
|
when :daily_tokens
|
|
210
|
-
effective_daily_token_limit && (ensure_daily_reset
|
|
212
|
+
effective_daily_token_limit && (ensure_daily_reset!
|
|
213
|
+
effective_daily_token_limit - daily_tokens_used)
|
|
211
214
|
when :monthly_tokens
|
|
212
|
-
effective_monthly_token_limit && (ensure_monthly_reset
|
|
215
|
+
effective_monthly_token_limit && (ensure_monthly_reset!
|
|
216
|
+
effective_monthly_token_limit - monthly_tokens_used)
|
|
213
217
|
when :daily_executions
|
|
214
|
-
effective_daily_execution_limit && (ensure_daily_reset
|
|
218
|
+
effective_daily_execution_limit && (ensure_daily_reset!
|
|
219
|
+
effective_daily_execution_limit - daily_executions_count)
|
|
215
220
|
when :monthly_executions
|
|
216
|
-
effective_monthly_execution_limit && (ensure_monthly_reset
|
|
221
|
+
effective_monthly_execution_limit && (ensure_monthly_reset!
|
|
222
|
+
effective_monthly_execution_limit - monthly_executions_count)
|
|
217
223
|
end
|
|
218
224
|
end
|
|
219
225
|
|
|
@@ -71,19 +71,19 @@ module RubyLLM
|
|
|
71
71
|
last_exec = executions.order(created_at: :desc).pick(:created_at, :status)
|
|
72
72
|
|
|
73
73
|
update_columns(
|
|
74
|
-
daily_cost_spent:
|
|
75
|
-
daily_tokens_used:
|
|
76
|
-
daily_executions_count:
|
|
77
|
-
daily_error_count:
|
|
78
|
-
daily_reset_date:
|
|
79
|
-
|
|
80
|
-
monthly_cost_spent:
|
|
81
|
-
monthly_tokens_used:
|
|
74
|
+
daily_cost_spent: daily_stats[:cost],
|
|
75
|
+
daily_tokens_used: daily_stats[:tokens],
|
|
76
|
+
daily_executions_count: daily_stats[:count],
|
|
77
|
+
daily_error_count: daily_stats[:errors],
|
|
78
|
+
daily_reset_date: today,
|
|
79
|
+
|
|
80
|
+
monthly_cost_spent: monthly_stats[:cost],
|
|
81
|
+
monthly_tokens_used: monthly_stats[:tokens],
|
|
82
82
|
monthly_executions_count: monthly_stats[:count],
|
|
83
|
-
monthly_error_count:
|
|
84
|
-
monthly_reset_date:
|
|
83
|
+
monthly_error_count: monthly_stats[:errors],
|
|
84
|
+
monthly_reset_date: bom,
|
|
85
85
|
|
|
86
|
-
last_execution_at:
|
|
86
|
+
last_execution_at: last_exec&.first,
|
|
87
87
|
last_execution_status: last_exec&.last
|
|
88
88
|
)
|
|
89
89
|
|
|
@@ -120,7 +120,7 @@ module RubyLLM
|
|
|
120
120
|
Arel.sql("COALESCE(SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END), 0)")
|
|
121
121
|
)
|
|
122
122
|
|
|
123
|
-
{
|
|
123
|
+
{cost: agg[0], tokens: agg[1], count: agg[2], errors: agg[3]}
|
|
124
124
|
end
|
|
125
125
|
end
|
|
126
126
|
end
|
|
@@ -32,10 +32,10 @@ module RubyLLM
|
|
|
32
32
|
included do
|
|
33
33
|
# Association to executions via tenant_id
|
|
34
34
|
has_many :executions,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
class_name: "RubyLLM::Agents::Execution",
|
|
36
|
+
primary_key: :tenant_id,
|
|
37
|
+
foreign_key: :tenant_id,
|
|
38
|
+
inverse_of: false
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
# Cost queries
|
|
@@ -251,7 +251,7 @@ module RubyLLM
|
|
|
251
251
|
Arel.sql("SUM(total_tokens)"),
|
|
252
252
|
Arel.sql("COUNT(*)")
|
|
253
253
|
).to_h do |agent_type, total_cost, total_tokens, count|
|
|
254
|
-
[agent_type, {
|
|
254
|
+
[agent_type, {cost: total_cost || 0, tokens: total_tokens || 0, count: count}]
|
|
255
255
|
end
|
|
256
256
|
end
|
|
257
257
|
|
|
@@ -269,7 +269,7 @@ module RubyLLM
|
|
|
269
269
|
Arel.sql("SUM(total_tokens)"),
|
|
270
270
|
Arel.sql("COUNT(*)")
|
|
271
271
|
).to_h do |model_id, total_cost, total_tokens, count|
|
|
272
|
-
[model_id, {
|
|
272
|
+
[model_id, {cost: total_cost || 0, tokens: total_tokens || 0, count: count}]
|
|
273
273
|
end
|
|
274
274
|
end
|
|
275
275
|
|
|
@@ -287,7 +287,7 @@ module RubyLLM
|
|
|
287
287
|
Arel.sql("SUM(total_tokens)"),
|
|
288
288
|
Arel.sql("COUNT(*)")
|
|
289
289
|
).to_h do |date, total_cost, total_tokens, count|
|
|
290
|
-
[date.to_date, {
|
|
290
|
+
[date.to_date, {cost: total_cost || 0, tokens: total_tokens || 0, count: count}]
|
|
291
291
|
end
|
|
292
292
|
end
|
|
293
293
|
|
|
@@ -71,7 +71,7 @@ module RubyLLM
|
|
|
71
71
|
image_generators = RubyLLM::Agents::ImageGenerator.descendants.map(&:name).compact
|
|
72
72
|
|
|
73
73
|
(agents + embedders + speakers + transcribers + image_generators).uniq
|
|
74
|
-
rescue
|
|
74
|
+
rescue => e
|
|
75
75
|
Rails.logger.error("[RubyLLM::Agents] Error loading agents from file system: #{e.message}")
|
|
76
76
|
[]
|
|
77
77
|
end
|
|
@@ -81,7 +81,7 @@ module RubyLLM
|
|
|
81
81
|
# @return [Array<String>] Agent class names with execution records
|
|
82
82
|
def execution_agents
|
|
83
83
|
Execution.distinct.pluck(:agent_type).compact
|
|
84
|
-
rescue
|
|
84
|
+
rescue => e
|
|
85
85
|
Rails.logger.error("[RubyLLM::Agents] Error loading agents from executions: #{e.message}")
|
|
86
86
|
[]
|
|
87
87
|
end
|
|
@@ -149,7 +149,7 @@ module RubyLLM
|
|
|
149
149
|
return nil unless klass.respond_to?(method_name)
|
|
150
150
|
|
|
151
151
|
klass.public_send(method_name)
|
|
152
|
-
rescue
|
|
152
|
+
rescue
|
|
153
153
|
nil
|
|
154
154
|
end
|
|
155
155
|
|
|
@@ -159,8 +159,8 @@ module RubyLLM
|
|
|
159
159
|
# @return [Hash] Statistics hash
|
|
160
160
|
def fetch_stats(agent_type)
|
|
161
161
|
Execution.stats_for(agent_type, period: :all_time)
|
|
162
|
-
rescue
|
|
163
|
-
{
|
|
162
|
+
rescue
|
|
163
|
+
{count: 0, total_cost: 0, total_tokens: 0, avg_duration_ms: 0, success_rate: 0, error_rate: 0}
|
|
164
164
|
end
|
|
165
165
|
|
|
166
166
|
# Gets the timestamp of the last execution for an agent
|
|
@@ -169,7 +169,7 @@ module RubyLLM
|
|
|
169
169
|
# @return [Time, nil] Last execution time or nil
|
|
170
170
|
def last_execution_time(agent_type)
|
|
171
171
|
Execution.by_agent(agent_type).order(created_at: :desc).first&.created_at
|
|
172
|
-
rescue
|
|
172
|
+
rescue
|
|
173
173
|
nil
|
|
174
174
|
end
|
|
175
175
|
|
|
@@ -19,20 +19,151 @@
|
|
|
19
19
|
})();
|
|
20
20
|
</script>
|
|
21
21
|
|
|
22
|
+
<!-- Gruvbox-aware color palette: CSS custom properties swapped in .dark -->
|
|
23
|
+
<style>
|
|
24
|
+
:root {
|
|
25
|
+
/* Gray (Tailwind defaults) */
|
|
26
|
+
--c-gray-50: 249 250 251; --c-gray-100: 243 244 246; --c-gray-200: 229 231 235;
|
|
27
|
+
--c-gray-300: 209 213 219; --c-gray-400: 156 163 175; --c-gray-500: 107 114 128;
|
|
28
|
+
--c-gray-600: 75 85 99; --c-gray-700: 55 65 81; --c-gray-800: 31 41 55;
|
|
29
|
+
--c-gray-900: 17 24 39; --c-gray-950: 3 7 18;
|
|
30
|
+
/* Blue */
|
|
31
|
+
--c-blue-50: 239 246 255; --c-blue-100: 219 234 254; --c-blue-200: 191 219 254;
|
|
32
|
+
--c-blue-300: 147 197 253; --c-blue-400: 96 165 250; --c-blue-500: 59 130 246;
|
|
33
|
+
--c-blue-600: 37 99 235; --c-blue-700: 29 78 216; --c-blue-800: 30 64 175;
|
|
34
|
+
--c-blue-900: 30 58 138; --c-blue-950: 23 37 84;
|
|
35
|
+
/* Red */
|
|
36
|
+
--c-red-50: 254 242 242; --c-red-100: 254 226 226; --c-red-200: 254 202 202;
|
|
37
|
+
--c-red-300: 252 165 165; --c-red-400: 248 113 113; --c-red-500: 239 68 68;
|
|
38
|
+
--c-red-600: 220 38 38; --c-red-700: 185 28 28; --c-red-800: 153 27 27;
|
|
39
|
+
--c-red-900: 127 29 29; --c-red-950: 69 10 10;
|
|
40
|
+
/* Green */
|
|
41
|
+
--c-green-50: 240 253 244; --c-green-100: 220 252 231; --c-green-200: 187 247 208;
|
|
42
|
+
--c-green-300: 134 239 172; --c-green-400: 74 222 128; --c-green-500: 34 197 94;
|
|
43
|
+
--c-green-600: 22 163 74; --c-green-700: 21 128 61; --c-green-800: 22 101 52;
|
|
44
|
+
--c-green-900: 20 83 45; --c-green-950: 5 46 22;
|
|
45
|
+
/* Yellow */
|
|
46
|
+
--c-yellow-50: 254 252 232; --c-yellow-100: 254 249 195; --c-yellow-200: 254 240 138;
|
|
47
|
+
--c-yellow-300: 253 224 71; --c-yellow-400: 250 204 21; --c-yellow-500: 234 179 8;
|
|
48
|
+
--c-yellow-600: 202 138 4; --c-yellow-700: 161 98 7; --c-yellow-800: 133 77 14;
|
|
49
|
+
--c-yellow-900: 113 63 18; --c-yellow-950: 66 32 6;
|
|
50
|
+
/* Orange */
|
|
51
|
+
--c-orange-50: 255 247 237; --c-orange-100: 255 237 213; --c-orange-200: 254 215 170;
|
|
52
|
+
--c-orange-300: 253 186 116; --c-orange-400: 251 146 60; --c-orange-500: 249 115 22;
|
|
53
|
+
--c-orange-600: 234 88 12; --c-orange-700: 194 65 12; --c-orange-800: 154 52 18;
|
|
54
|
+
--c-orange-900: 124 45 18; --c-orange-950: 67 20 7;
|
|
55
|
+
/* Purple */
|
|
56
|
+
--c-purple-50: 250 245 255; --c-purple-100: 243 232 255; --c-purple-200: 233 213 255;
|
|
57
|
+
--c-purple-300: 216 180 254; --c-purple-400: 192 132 252; --c-purple-500: 168 85 247;
|
|
58
|
+
--c-purple-600: 147 51 234; --c-purple-700: 126 34 206; --c-purple-800: 107 33 168;
|
|
59
|
+
--c-purple-900: 88 28 135; --c-purple-950: 59 7 100;
|
|
60
|
+
/* Cyan */
|
|
61
|
+
--c-cyan-50: 236 254 255; --c-cyan-100: 207 250 254; --c-cyan-200: 165 243 252;
|
|
62
|
+
--c-cyan-300: 103 232 249; --c-cyan-400: 34 211 238; --c-cyan-500: 6 182 212;
|
|
63
|
+
--c-cyan-600: 8 145 178; --c-cyan-700: 14 116 144; --c-cyan-800: 21 94 117;
|
|
64
|
+
--c-cyan-900: 22 78 99; --c-cyan-950: 8 51 68;
|
|
65
|
+
/* Pink */
|
|
66
|
+
--c-pink-50: 253 242 248; --c-pink-100: 252 231 243; --c-pink-200: 251 207 232;
|
|
67
|
+
--c-pink-300: 249 168 212; --c-pink-400: 244 114 182; --c-pink-500: 236 72 153;
|
|
68
|
+
--c-pink-600: 219 39 119; --c-pink-700: 190 24 93; --c-pink-800: 157 23 77;
|
|
69
|
+
--c-pink-900: 131 24 67; --c-pink-950: 80 7 36;
|
|
70
|
+
/* Amber */
|
|
71
|
+
--c-amber-50: 255 251 235; --c-amber-100: 254 243 199; --c-amber-200: 253 230 138;
|
|
72
|
+
--c-amber-300: 252 211 77; --c-amber-400: 251 191 36; --c-amber-500: 245 158 11;
|
|
73
|
+
--c-amber-600: 217 119 6; --c-amber-700: 180 83 9; --c-amber-800: 146 64 14;
|
|
74
|
+
--c-amber-900: 120 53 15; --c-amber-950: 69 26 3;
|
|
75
|
+
}
|
|
76
|
+
.dark {
|
|
77
|
+
/* Gray → Gruvbox bg/fg */
|
|
78
|
+
--c-gray-50: 251 241 199; --c-gray-100: 235 219 178; --c-gray-200: 213 196 161;
|
|
79
|
+
--c-gray-300: 189 174 147; --c-gray-400: 189 174 147; --c-gray-500: 168 153 132;
|
|
80
|
+
--c-gray-600: 146 131 116; --c-gray-700: 102 92 84; --c-gray-800: 80 73 69;
|
|
81
|
+
--c-gray-900: 60 56 54; --c-gray-950: 40 40 40;
|
|
82
|
+
/* Blue → Gruvbox aqua (#83a598 / #458588) */
|
|
83
|
+
--c-blue-50: 195 215 205; --c-blue-100: 174 199 188; --c-blue-200: 153 182 170;
|
|
84
|
+
--c-blue-300: 131 165 152; --c-blue-400: 100 149 144; --c-blue-500: 69 133 136;
|
|
85
|
+
--c-blue-600: 58 112 115; --c-blue-700: 48 93 95; --c-blue-800: 38 73 75;
|
|
86
|
+
--c-blue-900: 28 55 57; --c-blue-950: 20 40 42;
|
|
87
|
+
/* Red → Gruvbox red (#fb4934 / #cc241d) */
|
|
88
|
+
--c-red-50: 253 165 155; --c-red-100: 253 135 122; --c-red-200: 252 104 87;
|
|
89
|
+
--c-red-300: 251 73 52; --c-red-400: 228 55 41; --c-red-500: 251 89 66;
|
|
90
|
+
--c-red-600: 204 36 29; --c-red-700: 136 24 19; --c-red-800: 102 18 14;
|
|
91
|
+
--c-red-900: 72 12 10; --c-red-950: 50 8 7;
|
|
92
|
+
/* Green → Gruvbox green (#b8bb26 / #98971a) */
|
|
93
|
+
--c-green-50: 225 227 145; --c-green-100: 213 215 112; --c-green-200: 199 201 75;
|
|
94
|
+
--c-green-300: 184 187 38; --c-green-400: 168 169 32; --c-green-500: 152 151 26;
|
|
95
|
+
--c-green-600: 126 125 22; --c-green-700: 101 100 17; --c-green-800: 77 77 13;
|
|
96
|
+
--c-green-900: 55 55 9; --c-green-950: 38 38 6;
|
|
97
|
+
/* Yellow → Gruvbox yellow (#fabd2f / #d79921) */
|
|
98
|
+
--c-yellow-50: 253 225 155; --c-yellow-100: 252 215 121; --c-yellow-200: 251 202 84;
|
|
99
|
+
--c-yellow-300: 250 189 47; --c-yellow-400: 233 171 40; --c-yellow-500: 215 153 33;
|
|
100
|
+
--c-yellow-600: 179 127 27; --c-yellow-700: 143 102 22; --c-yellow-800: 109 78 17;
|
|
101
|
+
--c-yellow-900: 77 55 12; --c-yellow-950: 53 38 8;
|
|
102
|
+
/* Orange → Gruvbox orange (#fe8019 / #d65d0e) */
|
|
103
|
+
--c-orange-50: 255 197 140; --c-orange-100: 255 172 102; --c-orange-200: 254 150 64;
|
|
104
|
+
--c-orange-300: 254 128 25; --c-orange-400: 234 111 20; --c-orange-500: 214 93 14;
|
|
105
|
+
--c-orange-600: 178 77 12; --c-orange-700: 142 62 9; --c-orange-800: 108 47 7;
|
|
106
|
+
--c-orange-900: 76 33 5; --c-orange-950: 52 23 3;
|
|
107
|
+
/* Purple → Gruvbox purple (#d3869b / #b16286) */
|
|
108
|
+
--c-purple-50: 235 186 200; --c-purple-100: 227 168 184; --c-purple-200: 219 151 170;
|
|
109
|
+
--c-purple-300: 211 134 155; --c-purple-400: 194 116 145; --c-purple-500: 177 98 134;
|
|
110
|
+
--c-purple-600: 147 81 111; --c-purple-700: 118 65 89; --c-purple-800: 90 50 68;
|
|
111
|
+
--c-purple-900: 63 35 48; --c-purple-950: 43 24 33;
|
|
112
|
+
/* Cyan → Gruvbox green-cyan (#8ec07c / #689d6a) */
|
|
113
|
+
--c-cyan-50: 194 228 184; --c-cyan-100: 177 216 164; --c-cyan-200: 160 204 144;
|
|
114
|
+
--c-cyan-300: 142 192 124; --c-cyan-400: 123 175 115; --c-cyan-500: 104 157 106;
|
|
115
|
+
--c-cyan-600: 86 131 88; --c-cyan-700: 69 105 70; --c-cyan-800: 53 80 54;
|
|
116
|
+
--c-cyan-900: 37 57 38; --c-cyan-950: 26 40 27;
|
|
117
|
+
/* Pink → Gruvbox purple (no pink in Gruvbox) */
|
|
118
|
+
--c-pink-50: 235 186 200; --c-pink-100: 227 168 184; --c-pink-200: 219 151 170;
|
|
119
|
+
--c-pink-300: 211 134 155; --c-pink-400: 194 116 145; --c-pink-500: 177 98 134;
|
|
120
|
+
--c-pink-600: 147 81 111; --c-pink-700: 118 65 89; --c-pink-800: 90 50 68;
|
|
121
|
+
--c-pink-900: 63 35 48; --c-pink-950: 43 24 33;
|
|
122
|
+
/* Amber → Gruvbox yellow-orange */
|
|
123
|
+
--c-amber-50: 254 224 155; --c-amber-100: 253 213 121; --c-amber-200: 252 198 84;
|
|
124
|
+
--c-amber-300: 251 184 47; --c-amber-400: 235 162 37; --c-amber-500: 215 140 26;
|
|
125
|
+
--c-amber-600: 179 116 22; --c-amber-700: 143 93 17; --c-amber-800: 109 71 13;
|
|
126
|
+
--c-amber-900: 77 50 9; --c-amber-950: 53 35 6;
|
|
127
|
+
}
|
|
128
|
+
</style>
|
|
129
|
+
|
|
22
130
|
<!-- Tailwind CSS via CDN -->
|
|
23
131
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
24
132
|
|
|
25
133
|
<script>
|
|
26
134
|
tailwind.config = {
|
|
27
|
-
darkMode: 'class'
|
|
135
|
+
darkMode: 'class',
|
|
136
|
+
theme: {
|
|
137
|
+
extend: {
|
|
138
|
+
colors: (function() {
|
|
139
|
+
var families = ['gray','blue','red','green','yellow','orange','purple','cyan','pink','amber'];
|
|
140
|
+
var shades = [50,100,200,300,400,500,600,700,800,900,950];
|
|
141
|
+
var c = {};
|
|
142
|
+
families.forEach(function(f) {
|
|
143
|
+
c[f] = {};
|
|
144
|
+
shades.forEach(function(s) {
|
|
145
|
+
c[f][s] = 'rgb(var(--c-' + f + '-' + s + ') / <alpha-value>)';
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
return c;
|
|
149
|
+
})()
|
|
150
|
+
}
|
|
151
|
+
}
|
|
28
152
|
}
|
|
29
153
|
</script>
|
|
30
154
|
|
|
31
155
|
<!-- Highcharts for charts -->
|
|
32
156
|
<script src="https://code.highcharts.com/highcharts.js"></script>
|
|
33
157
|
|
|
34
|
-
<!--
|
|
158
|
+
<!-- Chart color helpers + Highcharts defaults -->
|
|
35
159
|
<script>
|
|
160
|
+
function chartColor(lightHex, darkHex) {
|
|
161
|
+
return document.documentElement.classList.contains('dark') ? darkHex : lightHex;
|
|
162
|
+
}
|
|
163
|
+
function chartColorAlpha(lightRgba, darkR, darkG, darkB, alpha) {
|
|
164
|
+
return document.documentElement.classList.contains('dark')
|
|
165
|
+
? 'rgba(' + darkR + ',' + darkG + ',' + darkB + ',' + alpha + ')' : lightRgba;
|
|
166
|
+
}
|
|
36
167
|
Highcharts.setOptions({
|
|
37
168
|
credits: { enabled: false },
|
|
38
169
|
chart: {
|
|
@@ -41,22 +172,22 @@
|
|
|
41
172
|
},
|
|
42
173
|
title: { text: null },
|
|
43
174
|
xAxis: {
|
|
44
|
-
labels: { style: { color: '#6B7280' } },
|
|
45
|
-
lineColor: 'rgba(107, 114, 128, 0.1)',
|
|
46
|
-
tickColor: 'rgba(107, 114, 128, 0.1)'
|
|
175
|
+
labels: { style: { color: chartColor('#6B7280', '#928374') } },
|
|
176
|
+
lineColor: chartColorAlpha('rgba(107, 114, 128, 0.1)', 146, 131, 116, 0.1),
|
|
177
|
+
tickColor: chartColorAlpha('rgba(107, 114, 128, 0.1)', 146, 131, 116, 0.1)
|
|
47
178
|
},
|
|
48
179
|
yAxis: {
|
|
49
|
-
labels: { style: { color: '#6B7280' } },
|
|
50
|
-
gridLineColor: 'rgba(107, 114, 128, 0.1)'
|
|
180
|
+
labels: { style: { color: chartColor('#6B7280', '#928374') } },
|
|
181
|
+
gridLineColor: chartColorAlpha('rgba(107, 114, 128, 0.1)', 146, 131, 116, 0.1)
|
|
51
182
|
},
|
|
52
183
|
legend: {
|
|
53
|
-
itemStyle: { color: '#6B7280' },
|
|
54
|
-
itemHoverStyle: { color: '#9CA3AF' }
|
|
184
|
+
itemStyle: { color: chartColor('#6B7280', '#928374') },
|
|
185
|
+
itemHoverStyle: { color: chartColor('#9CA3AF', '#bdae93') }
|
|
55
186
|
},
|
|
56
187
|
tooltip: {
|
|
57
|
-
backgroundColor: 'rgba(0, 0, 0, 0.85)',
|
|
188
|
+
backgroundColor: chartColorAlpha('rgba(0, 0, 0, 0.85)', 40, 40, 40, 0.95),
|
|
58
189
|
borderColor: 'transparent',
|
|
59
|
-
style: { color: '#E5E7EB', fontFamily: 'ui-monospace, monospace' }
|
|
190
|
+
style: { color: chartColor('#E5E7EB', '#ebdbb2'), fontFamily: 'ui-monospace, monospace' }
|
|
60
191
|
}
|
|
61
192
|
});
|
|
62
193
|
</script>
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
title: { text: null },
|
|
110
110
|
xAxis: {
|
|
111
111
|
type: 'datetime',
|
|
112
|
-
labels: { style: { color: '#6B7280', fontSize: '9px', fontFamily: 'ui-monospace, monospace' }, format: '{value:%b %d}' },
|
|
112
|
+
labels: { style: { color: chartColor('#6B7280', '#928374'), fontSize: '9px', fontFamily: 'ui-monospace, monospace' }, format: '{value:%b %d}' },
|
|
113
113
|
lineColor: 'transparent',
|
|
114
114
|
tickLength: 0,
|
|
115
115
|
gridLineWidth: 0
|
|
@@ -118,19 +118,19 @@
|
|
|
118
118
|
title: { text: null },
|
|
119
119
|
min: 0,
|
|
120
120
|
allowDecimals: false,
|
|
121
|
-
labels: { style: { color: '#6B7280', fontSize: '9px', fontFamily: 'ui-monospace, monospace' } },
|
|
122
|
-
gridLineColor: 'rgba(107, 114, 128, 0.08)'
|
|
121
|
+
labels: { style: { color: chartColor('#6B7280', '#928374'), fontSize: '9px', fontFamily: 'ui-monospace, monospace' } },
|
|
122
|
+
gridLineColor: chartColorAlpha('rgba(107, 114, 128, 0.08)', 146, 131, 116, 0.08)
|
|
123
123
|
},
|
|
124
124
|
legend: { enabled: false },
|
|
125
125
|
credits: { enabled: false },
|
|
126
126
|
tooltip: {
|
|
127
|
-
backgroundColor: 'rgba(0, 0, 0, 0.85)',
|
|
127
|
+
backgroundColor: chartColorAlpha('rgba(0, 0, 0, 0.85)', 40, 40, 40, 0.95),
|
|
128
128
|
borderColor: 'transparent',
|
|
129
129
|
borderRadius: 3,
|
|
130
|
-
style: { color: '#E5E7EB', fontSize: '10px', fontFamily: 'ui-monospace, monospace' },
|
|
130
|
+
style: { color: chartColor('#E5E7EB', '#ebdbb2'), fontSize: '10px', fontFamily: 'ui-monospace, monospace' },
|
|
131
131
|
shared: true,
|
|
132
132
|
formatter: function() {
|
|
133
|
-
let html = '<span style="color
|
|
133
|
+
let html = '<span style="color:' + chartColor('#9CA3AF', '#bdae93') + '">' + Highcharts.dateFormat('%b %d', this.x) + '</span>';
|
|
134
134
|
let cost = trendData.find(d => new Date(d.date).getTime() === this.x);
|
|
135
135
|
this.points.forEach(p => html += '<br/>' + p.series.name + ': <b>' + p.y + '</b>');
|
|
136
136
|
if (cost) html += '<br/>cost: <b>$' + cost.cost.toFixed(4) + '</b>';
|
|
@@ -148,14 +148,14 @@
|
|
|
148
148
|
{
|
|
149
149
|
name: 'errors',
|
|
150
150
|
data: errorData,
|
|
151
|
-
color: '#EF4444',
|
|
152
|
-
fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, 'rgba(239, 68, 68, 0.08)'], [1, 'rgba(239, 68, 68, 0)']] }
|
|
151
|
+
color: chartColor('#EF4444', '#fb4934'),
|
|
152
|
+
fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, chartColorAlpha('rgba(239, 68, 68, 0.08)', 251, 73, 52, 0.08)], [1, chartColorAlpha('rgba(239, 68, 68, 0)', 251, 73, 52, 0)]] }
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
155
|
name: 'success',
|
|
156
156
|
data: successData,
|
|
157
|
-
color: '#10B981',
|
|
158
|
-
fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, 'rgba(16, 185, 129, 0.08)'], [1, 'rgba(16, 185, 129, 0)']] }
|
|
157
|
+
color: chartColor('#10B981', '#b8bb26'),
|
|
158
|
+
fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, chartColorAlpha('rgba(16, 185, 129, 0.08)', 184, 187, 38, 0.08)], [1, chartColorAlpha('rgba(16, 185, 129, 0)', 184, 187, 38, 0)]] }
|
|
159
159
|
}
|
|
160
160
|
]
|
|
161
161
|
});
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
type: 'datetime',
|
|
61
61
|
min: now - getTimeRangeMs(range),
|
|
62
62
|
max: now,
|
|
63
|
-
labels: { style: { color: '#6B7280', fontSize: '9px', fontFamily: 'ui-monospace, monospace' }, format: '{value:' + fmt + '}' },
|
|
63
|
+
labels: { style: { color: chartColor('#6B7280', '#928374'), fontSize: '9px', fontFamily: 'ui-monospace, monospace' }, format: '{value:' + fmt + '}' },
|
|
64
64
|
lineColor: 'transparent',
|
|
65
65
|
tickLength: 0,
|
|
66
66
|
gridLineWidth: 0
|
|
@@ -69,19 +69,19 @@
|
|
|
69
69
|
title: { text: null },
|
|
70
70
|
min: 0,
|
|
71
71
|
allowDecimals: false,
|
|
72
|
-
labels: { style: { color: '#6B7280', fontSize: '9px', fontFamily: 'ui-monospace, monospace' } },
|
|
73
|
-
gridLineColor: 'rgba(107, 114, 128, 0.08)'
|
|
72
|
+
labels: { style: { color: chartColor('#6B7280', '#928374'), fontSize: '9px', fontFamily: 'ui-monospace, monospace' } },
|
|
73
|
+
gridLineColor: chartColorAlpha('rgba(107, 114, 128, 0.08)', 146, 131, 116, 0.08)
|
|
74
74
|
},
|
|
75
75
|
legend: { enabled: false },
|
|
76
76
|
credits: { enabled: false },
|
|
77
77
|
tooltip: {
|
|
78
|
-
backgroundColor: 'rgba(0, 0, 0, 0.85)',
|
|
78
|
+
backgroundColor: chartColorAlpha('rgba(0, 0, 0, 0.85)', 40, 40, 40, 0.95),
|
|
79
79
|
borderColor: 'transparent',
|
|
80
80
|
borderRadius: 3,
|
|
81
|
-
style: { color: '#E5E7EB', fontSize: '10px', fontFamily: 'ui-monospace, monospace' },
|
|
81
|
+
style: { color: chartColor('#E5E7EB', '#ebdbb2'), fontSize: '10px', fontFamily: 'ui-monospace, monospace' },
|
|
82
82
|
shared: true,
|
|
83
83
|
formatter: function() {
|
|
84
|
-
let html = '<span style="color
|
|
84
|
+
let html = '<span style="color:' + chartColor('#9CA3AF', '#bdae93') + '">' + Highcharts.dateFormat(fmt, this.x) + '</span>';
|
|
85
85
|
this.points.forEach(p => html += '<br/>' + p.series.name + ': <b>' + p.y + '</b>');
|
|
86
86
|
return html;
|
|
87
87
|
}
|
|
@@ -97,14 +97,14 @@
|
|
|
97
97
|
{
|
|
98
98
|
name: 'errors',
|
|
99
99
|
data: toDatetimePoints(data.series[1].data, range),
|
|
100
|
-
color: '#EF4444',
|
|
101
|
-
fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, 'rgba(239, 68, 68, 0.08)'], [1, 'rgba(239, 68, 68, 0)']] }
|
|
100
|
+
color: chartColor('#EF4444', '#fb4934'),
|
|
101
|
+
fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, chartColorAlpha('rgba(239, 68, 68, 0.08)', 251, 73, 52, 0.08)], [1, chartColorAlpha('rgba(239, 68, 68, 0)', 251, 73, 52, 0)]] }
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
name: 'success',
|
|
105
105
|
data: toDatetimePoints(data.series[0].data, range),
|
|
106
|
-
color: '#10B981',
|
|
107
|
-
fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, 'rgba(16, 185, 129, 0.08)'], [1, 'rgba(16, 185, 129, 0)']] }
|
|
106
|
+
color: chartColor('#10B981', '#b8bb26'),
|
|
107
|
+
fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, chartColorAlpha('rgba(16, 185, 129, 0.08)', 184, 187, 38, 0.08)], [1, chartColorAlpha('rgba(16, 185, 129, 0)', 184, 187, 38, 0)]] }
|
|
108
108
|
}
|
|
109
109
|
]
|
|
110
110
|
});
|
|
@@ -439,6 +439,19 @@
|
|
|
439
439
|
<pre id="user-prompt-content" class="hidden bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-gray-100 rounded p-4 text-xs overflow-x-auto max-h-96 font-mono whitespace-pre-wrap"><%= @execution.user_prompt %></pre>
|
|
440
440
|
<% end %>
|
|
441
441
|
|
|
442
|
+
<!-- ── assistant prompt ──────────────────── -->
|
|
443
|
+
<% if @execution.respond_to?(:assistant_prompt) && @execution.assistant_prompt.present? %>
|
|
444
|
+
<div class="flex items-center gap-3 mt-6 mb-3">
|
|
445
|
+
<span class="text-[10px] font-medium text-gray-400 dark:text-gray-600 uppercase tracking-widest font-mono">assistant prompt</span>
|
|
446
|
+
<div class="flex-1 border-t border-gray-200 dark:border-gray-800"></div>
|
|
447
|
+
<button type="button" onclick="togglePrompt('assistant')" class="font-mono text-xs text-gray-400 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">
|
|
448
|
+
<span id="assistant-prompt-toggle">expand</span>
|
|
449
|
+
</button>
|
|
450
|
+
</div>
|
|
451
|
+
<p id="assistant-prompt-preview" class="text-xs text-gray-600 dark:text-gray-300 font-mono bg-gray-50 dark:bg-gray-900 rounded p-3 truncate"><%= @execution.assistant_prompt.truncate(150) %></p>
|
|
452
|
+
<pre id="assistant-prompt-content" class="hidden bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-gray-100 rounded p-4 text-xs overflow-x-auto max-h-96 font-mono whitespace-pre-wrap"><%= @execution.assistant_prompt %></pre>
|
|
453
|
+
<% end %>
|
|
454
|
+
|
|
442
455
|
<!-- ── conversation ──────────────────── -->
|
|
443
456
|
<% if @execution.respond_to?(:messages_count) && @execution.messages_count.to_i > 0 %>
|
|
444
457
|
<%
|
|
@@ -22,11 +22,11 @@ module RubyLlmAgents
|
|
|
22
22
|
argument :params, type: :array, default: [], banner: "param[:required|:default] param[:required|:default]"
|
|
23
23
|
|
|
24
24
|
class_option :model, type: :string, default: "gemini-2.0-flash",
|
|
25
|
-
|
|
25
|
+
desc: "The LLM model to use"
|
|
26
26
|
class_option :temperature, type: :numeric, default: 0.0,
|
|
27
|
-
|
|
27
|
+
desc: "The temperature setting (0.0-1.0)"
|
|
28
28
|
class_option :cache, type: :string, default: nil,
|
|
29
|
-
|
|
29
|
+
desc: "Cache TTL (e.g., '1.hour', '30.minutes')"
|
|
30
30
|
|
|
31
31
|
def ensure_base_class_and_skill_file
|
|
32
32
|
agents_dir = "app/agents"
|
|
@@ -80,7 +80,7 @@ module RubyLlmAgents
|
|
|
80
80
|
if p.required?
|
|
81
81
|
"#{p.name}: value"
|
|
82
82
|
else
|
|
83
|
-
"#{p.name}: #{p.default ||
|
|
83
|
+
"#{p.name}: #{p.default || "value"}"
|
|
84
84
|
end
|
|
85
85
|
end.join(", ")
|
|
86
86
|
end
|
|
@@ -17,17 +17,17 @@ module RubyLlmAgents
|
|
|
17
17
|
source_root File.expand_path("templates", __dir__)
|
|
18
18
|
|
|
19
19
|
class_option :model, type: :string, default: "rembg",
|
|
20
|
-
|
|
20
|
+
desc: "The segmentation model to use"
|
|
21
21
|
class_option :output_format, type: :string, default: "png",
|
|
22
|
-
|
|
22
|
+
desc: "Output format (png, webp)"
|
|
23
23
|
class_option :refine_edges, type: :boolean, default: false,
|
|
24
|
-
|
|
24
|
+
desc: "Enable edge refinement"
|
|
25
25
|
class_option :alpha_matting, type: :boolean, default: false,
|
|
26
|
-
|
|
26
|
+
desc: "Enable alpha matting for better edges"
|
|
27
27
|
class_option :return_mask, type: :boolean, default: false,
|
|
28
|
-
|
|
28
|
+
desc: "Also return the segmentation mask"
|
|
29
29
|
class_option :cache, type: :string, default: nil,
|
|
30
|
-
|
|
30
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
31
31
|
|
|
32
32
|
def ensure_base_class_and_skill_file
|
|
33
33
|
images_dir = "app/agents/images"
|