ruby_llm 1.8.1 → 1.8.2

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 (27) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/lib/generators/ruby_llm/chat_ui/chat_ui_generator.rb +117 -69
  4. data/lib/generators/ruby_llm/chat_ui/templates/controllers/chats_controller.rb.tt +12 -12
  5. data/lib/generators/ruby_llm/chat_ui/templates/controllers/messages_controller.rb.tt +7 -7
  6. data/lib/generators/ruby_llm/chat_ui/templates/controllers/models_controller.rb.tt +4 -4
  7. data/lib/generators/ruby_llm/chat_ui/templates/jobs/chat_response_job.rb.tt +6 -6
  8. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_chat.html.erb.tt +4 -4
  9. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_form.html.erb.tt +5 -5
  10. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/index.html.erb.tt +5 -5
  11. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/new.html.erb.tt +4 -4
  12. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/show.html.erb.tt +8 -8
  13. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_form.html.erb.tt +5 -5
  14. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_message.html.erb.tt +9 -6
  15. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_tool_calls.html.erb.tt +7 -0
  16. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt +5 -5
  17. data/lib/generators/ruby_llm/chat_ui/templates/views/models/_model.html.erb.tt +9 -9
  18. data/lib/generators/ruby_llm/chat_ui/templates/views/models/index.html.erb.tt +4 -6
  19. data/lib/generators/ruby_llm/chat_ui/templates/views/models/show.html.erb.tt +11 -11
  20. data/lib/generators/ruby_llm/generator_helpers.rb +131 -87
  21. data/lib/generators/ruby_llm/install/install_generator.rb +75 -79
  22. data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +1 -1
  23. data/lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +88 -85
  24. data/lib/ruby_llm/active_record/acts_as.rb +11 -2
  25. data/lib/ruby_llm/connection.rb +1 -1
  26. data/lib/ruby_llm/version.rb +1 -1
  27. metadata +2 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8662c9b8b38e5941ea7e66882d59e8583989135285bc4b7eaaf5b83c8c2326e
4
- data.tar.gz: 33c168dc4d68d4cffb18bb0761adc42da51288a43aee78633d30f669bffaa47f
3
+ metadata.gz: 336eefa156c3f1b789ed32054beeb65b803dfa93c346274b4e812dc431bd6faf
4
+ data.tar.gz: 11f2c00c1eac1f24ad8beab2c4994fda980ac260e6481b261f3b0a515cc419a2
5
5
  SHA512:
6
- metadata.gz: 6f94e7adcf5b6f50aca97718c615d8dfa681a483da841ca8214f3970ca918a2a8e384f07a494dad9db83da269068a502ab8caf14a441a2ecb86909617e06fdf9
7
- data.tar.gz: 8342ae03bb413eb4b65b55c73629b1729b319e96e6976172fcaaa8ed19231280b5773eb8acccf4f563d63c801a78a03b20be5552189f86a4a7e435fb426c354f
6
+ metadata.gz: e4499bb85b6709d8fb2ff5e61d064f2352e265e03fa84b6f9aa1cba122c441f4239edc8e4ad5f9621fa4965411327d77a880b7496c145bcc2a3664ff4244545d
7
+ data.tar.gz: 440b540b7c514e72d1f4d916e04fe489cde96feb64f0699e1f7502b698f37d682b2e77b743efac212b259712553eb61703aae67e0a666fb0d05f02177382db38
data/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  Battle tested at [<picture><source media="(prefers-color-scheme: dark)" srcset="https://chatwithwork.com/logotype-dark.svg"><img src="https://chatwithwork.com/logotype.svg" alt="Chat with Work" height="30" align="absmiddle"></picture>](https://chatwithwork.com) — *Claude Code for your documents*
11
11
 
12
12
  [![Gem Version](https://badge.fury.io/rb/ruby_llm.svg?a=10)](https://badge.fury.io/rb/ruby_llm)
13
- [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
13
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)
14
14
  [![Gem Downloads](https://img.shields.io/gem/dt/ruby_llm)](https://rubygems.org/gems/ruby_llm)
15
15
  [![codecov](https://codecov.io/gh/crmne/ruby_llm/branch/main/graph/badge.svg?a=2)](https://codecov.io/gh/crmne/ruby_llm)
16
16
 
@@ -71,7 +71,7 @@ RubyLLM.embed "Ruby is elegant and expressive"
71
71
 
72
72
  ```ruby
73
73
  # Moderate content for safety
74
- RubyLLM.moderate("Check if this text is safe").flagged? # => false
74
+ RubyLLM.moderate "Check if this text is safe"
75
75
  ```
76
76
 
77
77
  ```ruby
@@ -139,10 +139,10 @@ end
139
139
  ## Rails
140
140
 
141
141
  ```bash
142
- # Install database models
142
+ # Install Rails Integration
143
143
  rails generate ruby_llm:install
144
144
 
145
- # Add chat UI (optional)
145
+ # Add Chat UI (optional)
146
146
  rails generate ruby_llm:chat_ui
147
147
  ```
148
148
 
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rails/generators'
4
+ require_relative '../generator_helpers'
4
5
 
5
6
  module RubyLLM
6
7
  module Generators
7
8
  # Generates a simple chat UI scaffold for RubyLLM
8
9
  class ChatUIGenerator < Rails::Generators::Base
10
+ include RubyLLM::Generators::GeneratorHelpers
11
+
9
12
  source_root File.expand_path('templates', __dir__)
10
13
 
11
14
  namespace 'ruby_llm:chat_ui'
@@ -15,102 +18,148 @@ module RubyLLM
15
18
  desc 'Creates a chat UI scaffold with Turbo streaming\n' \
16
19
  'Usage: rails g ruby_llm:chat_ui [chat:ChatName] [message:MessageName] ...'
17
20
 
18
- def parse_model_mappings
19
- @model_names = {
20
- chat: 'Chat',
21
- message: 'Message',
22
- tool_call: 'ToolCall',
23
- model: 'Model'
24
- }
25
-
26
- model_mappings.each do |mapping|
27
- if mapping.include?(':')
28
- key, value = mapping.split(':', 2)
29
- @model_names[key.to_sym] = value.classify
30
- end
31
- end
21
+ def check_model_exists
22
+ model_path = "app/models/#{message_model_name.underscore}.rb"
23
+ return if File.exist?(model_path)
32
24
 
33
- @model_names
34
- end
25
+ # Build the argument string for the install/upgrade commands
26
+ args = []
27
+ args << "chat:#{chat_model_name}" if chat_model_name != 'Chat'
28
+ args << "message:#{message_model_name}" if message_model_name != 'Message'
29
+ args << "model:#{model_model_name}" if model_model_name != 'Model'
30
+ args << "tool_call:#{tool_call_model_name}" if tool_call_model_name != 'ToolCall'
31
+ arg_string = args.any? ? " #{args.join(' ')}" : ''
35
32
 
36
- %i[chat message model].each do |type|
37
- define_method("#{type}_model_name") do
38
- @model_names ||= parse_model_mappings
39
- @model_names[type]
40
- end
33
+ raise Thor::Error, <<~ERROR
34
+ Model file not found: #{model_path}
41
35
 
42
- define_method("#{type}_table_name") do
43
- table_name_for(send("#{type}_model_name"))
44
- end
36
+ Please run the install generator first:
37
+ rails generate ruby_llm:install#{arg_string}
38
+
39
+ Or if upgrading from <= 1.6.x, run the upgrade generator:
40
+ rails generate ruby_llm:upgrade_to_v1_7#{arg_string}
41
+ ERROR
45
42
  end
46
43
 
47
44
  def create_views
45
+ # For namespaced models, use the proper Rails convention path
46
+ chat_view_path = chat_model_name.underscore.pluralize
47
+ message_view_path = message_model_name.underscore.pluralize
48
+ model_view_path = model_model_name.underscore.pluralize
49
+
48
50
  # Chat views
49
- template 'views/chats/index.html.erb', "app/views/#{chat_table_name}/index.html.erb"
50
- template 'views/chats/new.html.erb', "app/views/#{chat_table_name}/new.html.erb"
51
- template 'views/chats/show.html.erb', "app/views/#{chat_table_name}/show.html.erb"
51
+ template 'views/chats/index.html.erb', "app/views/#{chat_view_path}/index.html.erb"
52
+ template 'views/chats/new.html.erb', "app/views/#{chat_view_path}/new.html.erb"
53
+ template 'views/chats/show.html.erb', "app/views/#{chat_view_path}/show.html.erb"
52
54
  template 'views/chats/_chat.html.erb',
53
- "app/views/#{chat_table_name}/_#{chat_model_name.underscore}.html.erb"
54
- template 'views/chats/_form.html.erb', "app/views/#{chat_table_name}/_form.html.erb"
55
+ "app/views/#{chat_view_path}/_#{chat_model_name.demodulize.underscore}.html.erb"
56
+ template 'views/chats/_form.html.erb', "app/views/#{chat_view_path}/_form.html.erb"
55
57
 
56
58
  # Message views
57
59
  template 'views/messages/_message.html.erb',
58
- "app/views/#{message_table_name}/_#{message_model_name.underscore}.html.erb"
59
- template 'views/messages/_content.html.erb', "app/views/#{message_table_name}/_content.html.erb"
60
- template 'views/messages/_form.html.erb', "app/views/#{message_table_name}/_form.html.erb"
61
- template 'views/messages/create.turbo_stream.erb',
62
- "app/views/#{message_table_name}/create.turbo_stream.erb"
60
+ "app/views/#{message_view_path}/_#{message_model_name.demodulize.underscore}.html.erb"
61
+ template 'views/messages/_tool_calls.html.erb',
62
+ "app/views/#{message_view_path}/_tool_calls.html.erb"
63
+ template 'views/messages/_content.html.erb', "app/views/#{message_view_path}/_content.html.erb"
64
+ template 'views/messages/_form.html.erb', "app/views/#{message_view_path}/_form.html.erb"
65
+ template 'views/messages/create.turbo_stream.erb', "app/views/#{message_view_path}/create.turbo_stream.erb"
63
66
 
64
67
  # Model views
65
- template 'views/models/index.html.erb', "app/views/#{model_table_name}/index.html.erb"
66
- template 'views/models/show.html.erb', "app/views/#{model_table_name}/show.html.erb"
68
+ template 'views/models/index.html.erb', "app/views/#{model_view_path}/index.html.erb"
69
+ template 'views/models/show.html.erb', "app/views/#{model_view_path}/show.html.erb"
67
70
  template 'views/models/_model.html.erb',
68
- "app/views/#{model_table_name}/_#{model_model_name.underscore}.html.erb"
71
+ "app/views/#{model_view_path}/_#{model_model_name.demodulize.underscore}.html.erb"
69
72
  end
70
73
 
71
74
  def create_controllers
72
- template 'controllers/chats_controller.rb', "app/controllers/#{chat_table_name}_controller.rb"
73
- template 'controllers/messages_controller.rb', "app/controllers/#{message_table_name}_controller.rb"
74
- template 'controllers/models_controller.rb', "app/controllers/#{model_table_name}_controller.rb"
75
+ # For namespaced models, use the proper Rails convention path
76
+ chat_controller_path = chat_model_name.underscore.pluralize
77
+ message_controller_path = message_model_name.underscore.pluralize
78
+ model_controller_path = model_model_name.underscore.pluralize
79
+
80
+ template 'controllers/chats_controller.rb', "app/controllers/#{chat_controller_path}_controller.rb"
81
+ template 'controllers/messages_controller.rb', "app/controllers/#{message_controller_path}_controller.rb"
82
+ template 'controllers/models_controller.rb', "app/controllers/#{model_controller_path}_controller.rb"
75
83
  end
76
84
 
77
85
  def create_jobs
78
- template 'jobs/chat_response_job.rb', "app/jobs/#{chat_model_name.underscore}_response_job.rb"
86
+ template 'jobs/chat_response_job.rb', "app/jobs/#{variable_name_for(chat_model_name)}_response_job.rb"
79
87
  end
80
88
 
81
89
  def add_routes
82
- model_routes = <<~ROUTES.strip
83
- resources :#{model_table_name}, only: [:index, :show] do
84
- collection do
85
- post :refresh
90
+ # For namespaced models, use Rails convention with namespace blocks
91
+ if chat_model_name.include?('::')
92
+ namespace = chat_model_name.deconstantize.underscore
93
+ chat_resource = chat_model_name.demodulize.underscore.pluralize
94
+ message_resource = message_model_name.demodulize.underscore.pluralize
95
+ model_resource = model_model_name.demodulize.underscore.pluralize
96
+
97
+ routes_content = <<~ROUTES.strip
98
+ namespace :#{namespace} do
99
+ resources :#{model_resource}, only: [:index, :show] do
100
+ collection do
101
+ post :refresh
102
+ end
103
+ end
104
+ resources :#{chat_resource} do
105
+ resources :#{message_resource}, only: [:create]
106
+ end
86
107
  end
87
- end
88
- ROUTES
89
- route model_routes
90
- chat_routes = <<~ROUTES.strip
91
- resources :#{chat_table_name} do
92
- resources :#{message_table_name}, only: [:create]
93
- end
94
- ROUTES
95
- route chat_routes
108
+ ROUTES
109
+ route routes_content
110
+ else
111
+ model_routes = <<~ROUTES.strip
112
+ resources :#{model_table_name}, only: [:index, :show] do
113
+ collection do
114
+ post :refresh
115
+ end
116
+ end
117
+ ROUTES
118
+ route model_routes
119
+ chat_routes = <<~ROUTES.strip
120
+ resources :#{chat_table_name} do
121
+ resources :#{message_table_name}, only: [:create]
122
+ end
123
+ ROUTES
124
+ route chat_routes
125
+ end
96
126
  end
97
127
 
98
128
  def add_broadcasting_to_message_model
99
- msg_var = message_model_name.underscore
100
- chat_var = chat_model_name.underscore
101
- broadcasting_code = "broadcasts_to ->(#{msg_var}) { \"#{chat_var}_\#{#{msg_var}.#{chat_var}_id}\" }"
129
+ msg_var = variable_name_for(message_model_name)
130
+ chat_var = variable_name_for(chat_model_name)
131
+ msg_path = message_model_name.underscore
132
+
133
+ # For namespaced models, we need the association name which might be different
134
+ # e.g., for LLM::Message, the chat association might be :llm_chat
135
+ chat_association = chat_table_name.singularize
136
+
137
+ # Use Rails convention paths for partials
138
+ partial_path = message_model_name.underscore.pluralize
139
+
140
+ # For broadcasts, we need to explicitly set the partial path
141
+ # Turbo will pass the record with the demodulized name (e.g. 'message' for Llm::Message)
142
+ broadcasting_code = if message_model_name.include?('::')
143
+ partial_name = "#{partial_path}/#{message_model_name.demodulize.underscore}"
144
+ <<~RUBY.strip
145
+ broadcasts_to ->(#{msg_var}) { "#{chat_var}_\#{#{msg_var}.#{chat_association}_id}" },
146
+ partial: "#{partial_name}"
147
+ RUBY
148
+ else
149
+ "broadcasts_to ->(#{msg_var}) { \"#{chat_var}_\#{#{msg_var}.#{chat_association}_id}\" }"
150
+ end
102
151
 
103
152
  broadcast_append_chunk_method = <<-RUBY
104
153
 
105
154
  def broadcast_append_chunk(content)
106
- broadcast_append_to "#{chat_var}_\#{#{chat_var}_id}",
155
+ broadcast_append_to "#{chat_var}_\#{#{chat_association}_id}",
107
156
  target: "#{msg_var}_\#{id}_content",
108
- partial: "#{message_table_name}/content",
157
+ partial: "#{partial_path}/content",
109
158
  locals: { content: content }
110
159
  end
111
160
  RUBY
112
161
 
113
- inject_into_file "app/models/#{msg_var}.rb", before: "end\n" do
162
+ inject_into_file "app/models/#{msg_path}.rb", before: "end\n" do
114
163
  " #{broadcasting_code}\n#{broadcast_append_chunk_method}"
115
164
  end
116
165
  rescue Errno::ENOENT
@@ -122,18 +171,17 @@ module RubyLLM
122
171
  def display_post_install_message
123
172
  return unless behavior == :invoke
124
173
 
174
+ # Show the correct URL based on whether models are namespaced
175
+ url_path = if chat_model_name.include?('::')
176
+ chat_model_name.underscore.pluralize
177
+ else
178
+ chat_table_name
179
+ end
180
+
125
181
  say "\n ✅ Chat UI installed!", :green
126
- say "\n Start your server and visit http://localhost:3000/#{chat_table_name}", :cyan
182
+ say "\n Start your server and visit http://localhost:3000/#{url_path}", :cyan
127
183
  say "\n"
128
184
  end
129
-
130
- private
131
-
132
- def table_name_for(model_name)
133
- # Convert namespaced model names to proper table names
134
- # e.g., "Assistant::Chat" -> "assistant_chats" (not "assistant/chats")
135
- model_name.underscore.pluralize.tr('/', '_')
136
- end
137
185
  end
138
186
  end
139
187
  end
@@ -1,39 +1,39 @@
1
- class <%= chat_model_name.pluralize %>Controller < ApplicationController
2
- before_action :set_<%= chat_model_name.underscore %>, only: [:show]
1
+ class <%= chat_controller_class_name %> < ApplicationController
2
+ before_action :set_<%= chat_variable_name %>, only: [:show]
3
3
 
4
4
  def index
5
- @<%= chat_model_name.tableize %> = <%= chat_model_name %>.order(created_at: :desc)
5
+ @<%= chat_table_name %> = <%= chat_model_name %>.order(created_at: :desc)
6
6
  end
7
7
 
8
8
  def new
9
- @<%= chat_model_name.underscore %> = <%= chat_model_name %>.new
9
+ @<%= chat_variable_name %> = <%= chat_model_name %>.new
10
10
  @selected_model = params[:model]
11
11
  end
12
12
 
13
13
  def create
14
14
  return unless prompt.present?
15
15
 
16
- @<%= chat_model_name.underscore %> = <%= chat_model_name %>.create!(model: model)
17
- <%= chat_model_name %>ResponseJob.perform_later(@<%= chat_model_name.underscore %>.id, prompt)
16
+ @<%= chat_variable_name %> = <%= chat_model_name %>.create!(model: model)
17
+ <%= chat_job_class_name %>.perform_later(@<%= chat_variable_name %>.id, prompt)
18
18
 
19
- redirect_to @<%= chat_model_name.underscore %>, notice: '<%= chat_model_name.humanize %> was successfully created.'
19
+ redirect_to @<%= chat_variable_name %>, notice: '<%= chat_model_name.humanize %> was successfully created.'
20
20
  end
21
21
 
22
22
  def show
23
- @<%= message_model_name.underscore %> = @<%= chat_model_name.underscore %>.<%= message_model_name.tableize %>.build
23
+ @<%= message_variable_name %> = @<%= chat_variable_name %>.<%= message_table_name %>.build
24
24
  end
25
25
 
26
26
  private
27
27
 
28
- def set_<%= chat_model_name.underscore %>
29
- @<%= chat_model_name.underscore %> = <%= chat_model_name %>.find(params[:id])
28
+ def set_<%= chat_variable_name %>
29
+ @<%= chat_variable_name %> = <%= chat_model_name %>.find(params[:id])
30
30
  end
31
31
 
32
32
  def model
33
- params[:<%= chat_model_name.underscore %>][:model].presence
33
+ params[:<%= chat_variable_name %>][:model].presence
34
34
  end
35
35
 
36
36
  def prompt
37
- params[:<%= chat_model_name.underscore %>][:prompt]
37
+ params[:<%= chat_variable_name %>][:prompt]
38
38
  end
39
39
  end
@@ -1,24 +1,24 @@
1
- class <%= message_model_name.pluralize %>Controller < ApplicationController
2
- before_action :set_<%= chat_model_name.underscore %>
1
+ class <%= message_controller_class_name %> < ApplicationController
2
+ before_action :set_<%= chat_variable_name %>
3
3
 
4
4
  def create
5
5
  return unless content.present?
6
6
 
7
- <%= chat_model_name %>ResponseJob.perform_later(@<%= chat_model_name.underscore %>.id, content)
7
+ <%= chat_job_class_name %>.perform_later(@<%= chat_variable_name %>.id, content)
8
8
 
9
9
  respond_to do |format|
10
10
  format.turbo_stream
11
- format.html { redirect_to @<%= chat_model_name.underscore %> }
11
+ format.html { redirect_to @<%= chat_variable_name %> }
12
12
  end
13
13
  end
14
14
 
15
15
  private
16
16
 
17
- def set_<%= chat_model_name.underscore %>
18
- @<%= chat_model_name.underscore %> = <%= chat_model_name %>.find(params[:<%= chat_model_name.underscore %>_id])
17
+ def set_<%= chat_variable_name %>
18
+ @<%= chat_variable_name %> = <%= chat_model_name %>.find(params[:<%= chat_model_name.include?('::') ? chat_model_name.demodulize.underscore : chat_variable_name %>_id])
19
19
  end
20
20
 
21
21
  def content
22
- params[:<%= message_model_name.underscore %>][:content]
22
+ params[:<%= message_variable_name %>][:content]
23
23
  end
24
24
  end
@@ -1,14 +1,14 @@
1
- class <%= model_model_name.pluralize %>Controller < ApplicationController
1
+ class <%= model_controller_class_name %> < ApplicationController
2
2
  def index
3
- @<%= model_model_name.tableize %> = <%= model_model_name %>.all.group_by(&:provider)
3
+ @<%= model_table_name %> = <%= model_model_name %>.all
4
4
  end
5
5
 
6
6
  def show
7
- @<%= model_model_name.underscore %> = <%= model_model_name %>.find(params[:id])
7
+ @<%= model_variable_name %> = <%= model_model_name %>.find(params[:id])
8
8
  end
9
9
 
10
10
  def refresh
11
11
  <%= model_model_name %>.refresh!
12
- redirect_to <%= model_model_name.tableize %>_path, notice: "<%= model_model_name.pluralize %> refreshed successfully"
12
+ redirect_to <%= model_table_name %>_path, notice: "<%= model_model_name.pluralize %> refreshed successfully"
13
13
  end
14
14
  end
@@ -1,11 +1,11 @@
1
- class <%= chat_model_name %>ResponseJob < ApplicationJob
2
- def perform(<%= chat_model_name.underscore %>_id, content)
3
- <%= chat_model_name.underscore %> = <%= chat_model_name %>.find(<%= chat_model_name.underscore %>_id)
1
+ class <%= chat_job_class_name %> < ApplicationJob
2
+ def perform(<%= chat_variable_name %>_id, content)
3
+ <%= chat_variable_name %> = <%= chat_model_name %>.find(<%= chat_variable_name %>_id)
4
4
 
5
- <%= chat_model_name.underscore %>.ask(content) do |chunk|
5
+ <%= chat_variable_name %>.ask(content) do |chunk|
6
6
  if chunk.content && !chunk.content.blank?
7
- <%= message_model_name.underscore %> = <%= chat_model_name.underscore %>.<%= message_model_name.tableize %>.last
8
- <%= message_model_name.underscore %>.broadcast_append_chunk(chunk.content)
7
+ <%= message_variable_name %> = <%= chat_variable_name %>.<%= message_table_name %>.last
8
+ <%= message_variable_name %>.broadcast_append_chunk(chunk.content)
9
9
  end
10
10
  end
11
11
  end
@@ -1,16 +1,16 @@
1
- <div id="<%%= dom_id <%= chat_model_name.underscore %> %>">
1
+ <div id="<%%= dom_id <%= chat_model_name.demodulize.underscore %> %>">
2
2
  <div>
3
3
  <strong>Model:</strong>
4
- <%%= <%= chat_model_name.underscore %>.model_association.name %>
4
+ <%%= <%= chat_model_name.demodulize.underscore %>.<%= model_table_name.singularize %>&.name || 'Default' %>
5
5
  </div>
6
6
 
7
7
  <div>
8
8
  <strong>Messages:</strong>
9
- <%%= <%= chat_model_name.underscore %>.messages_association.count %>
9
+ <%%= <%= chat_model_name.demodulize.underscore %>.<%= message_table_name %>.count %>
10
10
  </div>
11
11
 
12
12
  <div>
13
13
  <strong>Created:</strong>
14
- <%%= <%= chat_model_name.underscore %>.created_at.strftime("%B %d, %Y at %I:%M %p") %>
14
+ <%%= <%= chat_model_name.demodulize.underscore %>.created_at.strftime("%B %d, %Y at %I:%M %p") %>
15
15
  </div>
16
16
  </div>
@@ -1,10 +1,10 @@
1
- <%%= form_with(model: <%= chat_model_name.underscore %>, url: <%= chat_model_name.tableize %>_path) do |form| %>
2
- <%% if <%= chat_model_name.underscore %>.errors.any? %>
1
+ <%%= form_with(model: <%= chat_variable_name %>, url: <%= chat_table_name %>_path) do |form| %>
2
+ <%% if <%= chat_variable_name %>.errors.any? %>
3
3
  <div style="color: red">
4
- <h2><%%= pluralize(<%= chat_model_name.underscore %>.errors.count, "error") %> prohibited this <%= chat_model_name.underscore.humanize.downcase %> from being saved:</h2>
4
+ <h2><%%= pluralize(<%= chat_variable_name %>.errors.count, "error") %> prohibited this <%= chat_table_name.singularize.humanize.downcase %> from being saved:</h2>
5
5
 
6
6
  <ul>
7
- <%% <%= chat_model_name.underscore %>.errors.each do |error| %>
7
+ <%% <%= chat_variable_name %>.errors.each do |error| %>
8
8
  <li><%%= error.full_message %></li>
9
9
  <%% end %>
10
10
  </ul>
@@ -24,6 +24,6 @@
24
24
  </div>
25
25
 
26
26
  <div>
27
- <%%= form.submit "Start new <%= chat_model_name.underscore.humanize.downcase %>" %>
27
+ <%%= form.submit "Start new <%= chat_table_name.singularize.humanize.downcase %>" %>
28
28
  </div>
29
29
  <%% end %>
@@ -4,13 +4,13 @@
4
4
 
5
5
  <h1><%= chat_model_name.pluralize %></h1>
6
6
 
7
- <div id="<%= chat_model_name.tableize %>">
8
- <%% @<%= chat_model_name.tableize %>.each do |<%= chat_model_name.underscore %>| %>
9
- <%%= render <%= chat_model_name.underscore %> %>
7
+ <div id="<%= chat_table_name %>">
8
+ <%% @<%= chat_table_name %>.each do |<%= chat_variable_name %>| %>
9
+ <%%= render <%= chat_variable_name %> %>
10
10
  <p>
11
- <%%= link_to "Show this <%= chat_model_name.underscore.humanize.downcase %>", <%= chat_model_name.underscore %> %>
11
+ <%%= link_to "Show this <%= chat_table_name.singularize.humanize.downcase %>", <%= chat_variable_name %> %>
12
12
  </p>
13
13
  <%% end %>
14
14
  </div>
15
15
 
16
- <%%= link_to "New <%= chat_model_name.underscore.humanize.downcase %>", new_<%= chat_model_name.underscore %>_path %>
16
+ <%%= link_to "New <%= chat_table_name.singularize.humanize.downcase %>", new_<%= chat_variable_name %>_path %>
@@ -1,11 +1,11 @@
1
- <%% content_for :title, "New <%= chat_model_name.underscore.humanize.downcase %>" %>
1
+ <%% content_for :title, "New <%= chat_table_name.singularize.humanize.downcase %>" %>
2
2
 
3
- <h1>New <%= chat_model_name.underscore.humanize.downcase %></h1>
3
+ <h1>New <%= chat_table_name.singularize.humanize.downcase %></h1>
4
4
 
5
- <%%= render "form", <%= chat_model_name.underscore %>: @<%= chat_model_name.underscore %> %>
5
+ <%%= render "form", <%= chat_variable_name %>: @<%= chat_variable_name %> %>
6
6
 
7
7
  <br>
8
8
 
9
9
  <div>
10
- <%%= link_to "Back to <%= chat_model_name.tableize.humanize.downcase %>", <%= chat_model_name.tableize %>_path %>
10
+ <%%= link_to "Back to <%= chat_table_name.humanize.downcase %>", <%= chat_table_name %>_path %>
11
11
  </div>
@@ -1,23 +1,23 @@
1
1
  <p style="color: green"><%%= notice %></p>
2
2
 
3
- <%%= turbo_stream_from "<%= chat_model_name.underscore %>_#{@<%= chat_model_name.underscore %>.id}" %>
3
+ <%%= turbo_stream_from "<%= chat_variable_name %>_#{@<%= chat_variable_name %>.id}" %>
4
4
 
5
5
  <%% content_for :title, "<%= chat_model_name %>" %>
6
6
 
7
- <h1><%= chat_model_name %> <%%= @<%= chat_model_name.underscore %>.id %></h1>
7
+ <h1><%= chat_model_name %> <%%= @<%= chat_variable_name %>.id %></h1>
8
8
 
9
- <p>Using <strong><%%= @<%= chat_model_name.underscore %>.model_association.name %></strong></p>
9
+ <p>Using <strong><%%= @<%= chat_variable_name %>.<%= model_table_name.singularize %>.name %></strong></p>
10
10
 
11
- <div id="<%= message_model_name.tableize %>">
12
- <%% @<%= chat_model_name.underscore %>.messages_association.where.not(id: nil).each do |<%= message_model_name.underscore %>| %>
13
- <%%= render "<%= message_model_name.tableize %>/<%= message_model_name.underscore %>", <%= message_model_name.underscore %>: <%= message_model_name.underscore %> %>
11
+ <div id="<%= message_table_name %>">
12
+ <%% @<%= chat_variable_name %>.<%= message_table_name %>.where.not(id: nil).each do |<%= message_variable_name %>| %>
13
+ <%%= render <%= message_variable_name %> %>
14
14
  <%% end %>
15
15
  </div>
16
16
 
17
17
  <div style="margin-top: 30px;">
18
- <%%= render "<%= message_model_name.tableize %>/form", <%= chat_model_name.underscore %>: @<%= chat_model_name.underscore %>, <%= message_model_name.underscore %>: @<%= message_model_name.underscore %> %>
18
+ <%%= render "<%= message_model_name.underscore.pluralize %>/form", <%= chat_variable_name %>: @<%= chat_variable_name %>, <%= message_variable_name %>: @<%= message_variable_name %> %>
19
19
  </div>
20
20
 
21
21
  <div style="margin-top: 20px;">
22
- <%%= link_to "Back to <%= chat_model_name.tableize.humanize.downcase %>", <%= chat_model_name.tableize %>_path %>
22
+ <%%= link_to "Back to <%= chat_table_name.humanize.downcase %>", <%= chat_table_name %>_path %>
23
23
  </div>
@@ -1,10 +1,10 @@
1
- <%%= form_with(model: [<%= chat_model_name.underscore %>, <%= message_model_name.underscore %>], id: "new_<%= message_model_name.underscore %>") do |form| %>
2
- <%% if <%= message_model_name.underscore %>.errors.any? %>
1
+ <%%= form_with(model: <%= message_variable_name %>, url: <%= chat_model_name.include?('::') ? "#{chat_model_name.split('::').first.underscore}_#{chat_model_name.demodulize.underscore}_#{message_model_name.demodulize.underscore.pluralize}_path(@#{chat_variable_name})" : "[@#{chat_variable_name}, #{message_variable_name}]" %>, id: "new_<%= message_variable_name %>") do |form| %>
2
+ <%% if <%= message_variable_name %>.errors.any? %>
3
3
  <div style="color: red">
4
- <h2><%%= pluralize(<%= message_model_name.underscore %>.errors.count, "error") %> prohibited this <%= message_model_name.underscore.humanize.downcase %> from being saved:</h2>
4
+ <h2><%%= pluralize(<%= message_variable_name %>.errors.count, "error") %> prohibited this <%= message_table_name.singularize.humanize.downcase %> from being saved:</h2>
5
5
 
6
6
  <ul>
7
- <%% <%= message_model_name.underscore %>.errors.each do |error| %>
7
+ <%% <%= message_variable_name %>.errors.each do |error| %>
8
8
  <li><%%= error.full_message %></li>
9
9
  <%% end %>
10
10
  </ul>
@@ -16,6 +16,6 @@
16
16
  </div>
17
17
 
18
18
  <div>
19
- <%%= form.submit "Send <%= message_model_name.underscore.humanize.downcase %>" %>
19
+ <%%= form.submit "Send <%= message_table_name.singularize.humanize.downcase %>" %>
20
20
  </div>
21
21
  <%% end %>
@@ -1,10 +1,13 @@
1
- <%%= tag.div id: dom_id(<%= message_model_name.underscore %>), class: "<%= message_model_name.underscore %>",
2
- style: "margin-bottom: 20px; padding: 10px; border-left: 3px solid #{<%= message_model_name.underscore %>.role == 'user' ? '#007bff' : '#28a745'};" do %>
1
+ <div id="<%= message_variable_name %>_<%%= <%= message_model_name.demodulize.underscore %>.id %>" class="<%= message_variable_name %>"
2
+ style="margin-bottom: 20px; padding: 10px; border-left: 3px solid <%%= <%= message_model_name.demodulize.underscore %>.role == 'user' ? '#007bff' : '#28a745' %>">
3
3
  <div style="font-weight: bold; margin-bottom: 5px;">
4
- <%%= <%= message_model_name.underscore %>.role&.capitalize %>
4
+ <%%= <%= message_model_name.demodulize.underscore %>.role&.capitalize %>
5
5
  </div>
6
- <div id="<%%= dom_id(<%= message_model_name.underscore %>) %>_content" style="white-space: pre-wrap;"><%%= <%= message_model_name.underscore %>.content %></div>
6
+ <div id="<%= message_variable_name %>_<%%= <%= message_model_name.demodulize.underscore %>.id %>_content" style="white-space: pre-wrap;"><%%= <%= message_model_name.demodulize.underscore %>.content %></div>
7
+ <%% if <%= message_model_name.demodulize.underscore %>.tool_call? %>
8
+ <%%= render "<%= message_model_name.underscore.pluralize %>/tool_calls", <%= message_model_name.demodulize.underscore %>: <%= message_model_name.demodulize.underscore %> %>
9
+ <%% end %>
7
10
  <div style="font-size: 0.85em; color: #666; margin-top: 5px;">
8
- <%%= <%= message_model_name.underscore %>.created_at&.strftime("%I:%M %p") %>
11
+ <%%= <%= message_model_name.demodulize.underscore %>.created_at&.strftime("%I:%M %p") %>
9
12
  </div>
10
- <%% end %>
13
+ </div>
@@ -0,0 +1,7 @@
1
+ <div style="display: flex; flex-direction: column; gap: 3px; align-items: flex-start; font-family: monospace;">
2
+ <%% <%= message_model_name.demodulize.underscore %>.<%= tool_call_variable_name.pluralize %>.each do |tool_call| %>
3
+ <div style="background: #eee; padding: 5px; border-radius: 4px;">
4
+ <%%= tool_call.name %>(<%%= tool_call.arguments.map { |k, v| "#{k}: #{v.inspect}" }.join(", ") %>)
5
+ </div>
6
+ <%% end %>
7
+ </div>
@@ -1,9 +1,9 @@
1
- <%%= turbo_stream.append "<%= message_model_name.tableize %>" do %>
2
- <%% @<%= chat_model_name.underscore %>.messages_association.last(2).each do |<%= message_model_name.underscore %>| %>
3
- <%%= render "<%= message_model_name.tableize %>/<%= message_model_name.underscore %>", <%= message_model_name.underscore %>: <%= message_model_name.underscore %> %>
1
+ <%%= turbo_stream.append "<%= message_table_name %>" do %>
2
+ <%% @<%= chat_variable_name %>.<%= message_table_name %>.last(2).each do |<%= message_variable_name %>| %>
3
+ <%%= render <%= message_variable_name %> %>
4
4
  <%% end %>
5
5
  <%% end %>
6
6
 
7
- <%%= turbo_stream.replace "new_<%= message_model_name.underscore %>" do %>
8
- <%%= render "<%= message_model_name.tableize %>/form", <%= chat_model_name.underscore %>: @<%= chat_model_name.underscore %>, <%= message_model_name.underscore %>: @<%= chat_model_name.underscore %>.messages_association.build %>
7
+ <%%= turbo_stream.replace "new_<%= message_variable_name %>" do %>
8
+ <%%= render "<%= message_model_name.underscore.pluralize %>/form", <%= chat_variable_name %>: @<%= chat_variable_name %>, <%= message_variable_name %>: @<%= chat_variable_name %>.<%= message_table_name %>.build %>
9
9
  <%% end %>