lex-llm 0.1.2 → 0.1.3

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 (165) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +7 -1
  4. data/Gemfile +1 -19
  5. data/README.md +22 -25
  6. data/lex-llm.gemspec +2 -2
  7. data/lib/legion/extensions/llm/agent.rb +366 -0
  8. data/lib/legion/extensions/llm/aliases.rb +42 -0
  9. data/lib/legion/extensions/llm/attachment.rb +229 -0
  10. data/lib/legion/extensions/llm/chat.rb +355 -0
  11. data/lib/legion/extensions/llm/chunk.rb +10 -0
  12. data/lib/legion/extensions/llm/configuration.rb +82 -0
  13. data/lib/legion/extensions/llm/connection.rb +134 -0
  14. data/lib/legion/extensions/llm/content.rb +81 -0
  15. data/lib/legion/extensions/llm/context.rb +33 -0
  16. data/lib/legion/extensions/llm/embedding.rb +33 -0
  17. data/lib/legion/extensions/llm/error.rb +116 -0
  18. data/lib/legion/extensions/llm/image.rb +109 -0
  19. data/lib/legion/extensions/llm/message.rb +111 -0
  20. data/lib/legion/extensions/llm/mime_type.rb +75 -0
  21. data/lib/legion/extensions/llm/model/info.rb +117 -0
  22. data/lib/legion/extensions/llm/model/modalities.rb +26 -0
  23. data/lib/legion/extensions/llm/model/pricing.rb +52 -0
  24. data/lib/legion/extensions/llm/model/pricing_category.rb +50 -0
  25. data/lib/legion/extensions/llm/model/pricing_tier.rb +37 -0
  26. data/lib/legion/extensions/llm/model.rb +11 -0
  27. data/lib/legion/extensions/llm/models.rb +514 -0
  28. data/lib/{lex_llm → legion/extensions/llm}/models_schema.json +1 -1
  29. data/lib/legion/extensions/llm/moderation.rb +60 -0
  30. data/lib/legion/extensions/llm/provider/open_ai_compatible.rb +240 -0
  31. data/lib/legion/extensions/llm/provider.rb +282 -0
  32. data/lib/legion/extensions/llm/routing/lane_key.rb +57 -0
  33. data/lib/legion/extensions/llm/routing/model_offering.rb +173 -0
  34. data/lib/legion/extensions/llm/routing.rb +11 -0
  35. data/lib/legion/extensions/llm/stream_accumulator.rb +209 -0
  36. data/lib/legion/extensions/llm/streaming.rb +181 -0
  37. data/lib/legion/extensions/llm/thinking.rb +53 -0
  38. data/lib/legion/extensions/llm/tokens.rb +51 -0
  39. data/lib/legion/extensions/llm/tool.rb +258 -0
  40. data/lib/legion/extensions/llm/tool_call.rb +29 -0
  41. data/lib/legion/extensions/llm/transcription.rb +39 -0
  42. data/lib/legion/extensions/llm/utils.rb +95 -0
  43. data/lib/legion/extensions/llm/version.rb +9 -0
  44. data/lib/legion/extensions/llm.rb +85 -6
  45. metadata +40 -122
  46. data/lib/generators/lex_llm/agent/agent_generator.rb +0 -36
  47. data/lib/generators/lex_llm/agent/templates/agent.rb.tt +0 -6
  48. data/lib/generators/lex_llm/agent/templates/instructions.txt.erb.tt +0 -0
  49. data/lib/generators/lex_llm/chat_ui/chat_ui_generator.rb +0 -256
  50. data/lib/generators/lex_llm/chat_ui/templates/controllers/chats_controller.rb.tt +0 -38
  51. data/lib/generators/lex_llm/chat_ui/templates/controllers/messages_controller.rb.tt +0 -21
  52. data/lib/generators/lex_llm/chat_ui/templates/controllers/models_controller.rb.tt +0 -14
  53. data/lib/generators/lex_llm/chat_ui/templates/helpers/messages_helper.rb.tt +0 -25
  54. data/lib/generators/lex_llm/chat_ui/templates/jobs/chat_response_job.rb.tt +0 -12
  55. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/chats/_chat.html.erb.tt +0 -16
  56. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/chats/_form.html.erb.tt +0 -31
  57. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/chats/index.html.erb.tt +0 -31
  58. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/chats/new.html.erb.tt +0 -9
  59. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/chats/show.html.erb.tt +0 -27
  60. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_assistant.html.erb.tt +0 -14
  61. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_content.html.erb.tt +0 -1
  62. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_error.html.erb.tt +0 -13
  63. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_form.html.erb.tt +0 -23
  64. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_system.html.erb.tt +0 -10
  65. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_tool.html.erb.tt +0 -2
  66. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_tool_calls.html.erb.tt +0 -4
  67. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_user.html.erb.tt +0 -14
  68. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/tool_calls/_default.html.erb.tt +0 -13
  69. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/tool_results/_default.html.erb.tt +0 -21
  70. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/models/_model.html.erb.tt +0 -17
  71. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/models/index.html.erb.tt +0 -40
  72. data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/models/show.html.erb.tt +0 -27
  73. data/lib/generators/lex_llm/chat_ui/templates/views/chats/_chat.html.erb.tt +0 -16
  74. data/lib/generators/lex_llm/chat_ui/templates/views/chats/_form.html.erb.tt +0 -29
  75. data/lib/generators/lex_llm/chat_ui/templates/views/chats/index.html.erb.tt +0 -28
  76. data/lib/generators/lex_llm/chat_ui/templates/views/chats/new.html.erb.tt +0 -11
  77. data/lib/generators/lex_llm/chat_ui/templates/views/chats/show.html.erb.tt +0 -25
  78. data/lib/generators/lex_llm/chat_ui/templates/views/messages/_assistant.html.erb.tt +0 -9
  79. data/lib/generators/lex_llm/chat_ui/templates/views/messages/_content.html.erb.tt +0 -1
  80. data/lib/generators/lex_llm/chat_ui/templates/views/messages/_error.html.erb.tt +0 -8
  81. data/lib/generators/lex_llm/chat_ui/templates/views/messages/_form.html.erb.tt +0 -21
  82. data/lib/generators/lex_llm/chat_ui/templates/views/messages/_system.html.erb.tt +0 -6
  83. data/lib/generators/lex_llm/chat_ui/templates/views/messages/_tool.html.erb.tt +0 -2
  84. data/lib/generators/lex_llm/chat_ui/templates/views/messages/_tool_calls.html.erb.tt +0 -4
  85. data/lib/generators/lex_llm/chat_ui/templates/views/messages/_user.html.erb.tt +0 -9
  86. data/lib/generators/lex_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt +0 -7
  87. data/lib/generators/lex_llm/chat_ui/templates/views/messages/tool_calls/_default.html.erb.tt +0 -8
  88. data/lib/generators/lex_llm/chat_ui/templates/views/messages/tool_results/_default.html.erb.tt +0 -16
  89. data/lib/generators/lex_llm/chat_ui/templates/views/models/_model.html.erb.tt +0 -15
  90. data/lib/generators/lex_llm/chat_ui/templates/views/models/index.html.erb.tt +0 -38
  91. data/lib/generators/lex_llm/chat_ui/templates/views/models/show.html.erb.tt +0 -17
  92. data/lib/generators/lex_llm/generator_helpers.rb +0 -214
  93. data/lib/generators/lex_llm/install/install_generator.rb +0 -109
  94. data/lib/generators/lex_llm/install/templates/add_references_to_chats_tool_calls_and_messages_migration.rb.tt +0 -9
  95. data/lib/generators/lex_llm/install/templates/chat_model.rb.tt +0 -3
  96. data/lib/generators/lex_llm/install/templates/create_chats_migration.rb.tt +0 -7
  97. data/lib/generators/lex_llm/install/templates/create_messages_migration.rb.tt +0 -19
  98. data/lib/generators/lex_llm/install/templates/create_models_migration.rb.tt +0 -39
  99. data/lib/generators/lex_llm/install/templates/create_tool_calls_migration.rb.tt +0 -21
  100. data/lib/generators/lex_llm/install/templates/initializer.rb.tt +0 -20
  101. data/lib/generators/lex_llm/install/templates/message_model.rb.tt +0 -4
  102. data/lib/generators/lex_llm/install/templates/model_model.rb.tt +0 -3
  103. data/lib/generators/lex_llm/install/templates/tool_call_model.rb.tt +0 -3
  104. data/lib/generators/lex_llm/schema/schema_generator.rb +0 -26
  105. data/lib/generators/lex_llm/schema/templates/schema.rb.tt +0 -2
  106. data/lib/generators/lex_llm/tool/templates/tool.rb.tt +0 -9
  107. data/lib/generators/lex_llm/tool/templates/tool_call.html.erb.tt +0 -13
  108. data/lib/generators/lex_llm/tool/templates/tool_result.html.erb.tt +0 -13
  109. data/lib/generators/lex_llm/tool/tool_generator.rb +0 -96
  110. data/lib/generators/lex_llm/upgrade_to_v1_10/templates/add_v1_10_message_columns.rb.tt +0 -19
  111. data/lib/generators/lex_llm/upgrade_to_v1_10/upgrade_to_v1_10_generator.rb +0 -50
  112. data/lib/generators/lex_llm/upgrade_to_v1_14/templates/add_v1_14_tool_call_columns.rb.tt +0 -7
  113. data/lib/generators/lex_llm/upgrade_to_v1_14/upgrade_to_v1_14_generator.rb +0 -49
  114. data/lib/generators/lex_llm/upgrade_to_v1_7/templates/migration.rb.tt +0 -145
  115. data/lib/generators/lex_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +0 -122
  116. data/lib/generators/lex_llm/upgrade_to_v1_9/templates/add_v1_9_message_columns.rb.tt +0 -15
  117. data/lib/generators/lex_llm/upgrade_to_v1_9/upgrade_to_v1_9_generator.rb +0 -49
  118. data/lib/lex_llm/active_record/acts_as.rb +0 -180
  119. data/lib/lex_llm/active_record/acts_as_legacy.rb +0 -503
  120. data/lib/lex_llm/active_record/chat_methods.rb +0 -468
  121. data/lib/lex_llm/active_record/message_methods.rb +0 -131
  122. data/lib/lex_llm/active_record/model_methods.rb +0 -76
  123. data/lib/lex_llm/active_record/payload_helpers.rb +0 -26
  124. data/lib/lex_llm/active_record/tool_call_methods.rb +0 -15
  125. data/lib/lex_llm/agent.rb +0 -365
  126. data/lib/lex_llm/aliases.rb +0 -38
  127. data/lib/lex_llm/attachment.rb +0 -223
  128. data/lib/lex_llm/chat.rb +0 -351
  129. data/lib/lex_llm/chunk.rb +0 -6
  130. data/lib/lex_llm/configuration.rb +0 -81
  131. data/lib/lex_llm/connection.rb +0 -130
  132. data/lib/lex_llm/content.rb +0 -77
  133. data/lib/lex_llm/context.rb +0 -29
  134. data/lib/lex_llm/embedding.rb +0 -29
  135. data/lib/lex_llm/error.rb +0 -112
  136. data/lib/lex_llm/image.rb +0 -105
  137. data/lib/lex_llm/message.rb +0 -107
  138. data/lib/lex_llm/mime_type.rb +0 -71
  139. data/lib/lex_llm/model/info.rb +0 -113
  140. data/lib/lex_llm/model/modalities.rb +0 -22
  141. data/lib/lex_llm/model/pricing.rb +0 -48
  142. data/lib/lex_llm/model/pricing_category.rb +0 -46
  143. data/lib/lex_llm/model/pricing_tier.rb +0 -33
  144. data/lib/lex_llm/model.rb +0 -7
  145. data/lib/lex_llm/models.rb +0 -506
  146. data/lib/lex_llm/moderation.rb +0 -56
  147. data/lib/lex_llm/provider/open_ai_compatible.rb +0 -219
  148. data/lib/lex_llm/provider.rb +0 -278
  149. data/lib/lex_llm/railtie.rb +0 -35
  150. data/lib/lex_llm/routing/lane_key.rb +0 -51
  151. data/lib/lex_llm/routing/model_offering.rb +0 -169
  152. data/lib/lex_llm/routing.rb +0 -7
  153. data/lib/lex_llm/stream_accumulator.rb +0 -203
  154. data/lib/lex_llm/streaming.rb +0 -175
  155. data/lib/lex_llm/thinking.rb +0 -49
  156. data/lib/lex_llm/tokens.rb +0 -47
  157. data/lib/lex_llm/tool.rb +0 -254
  158. data/lib/lex_llm/tool_call.rb +0 -25
  159. data/lib/lex_llm/transcription.rb +0 -35
  160. data/lib/lex_llm/utils.rb +0 -91
  161. data/lib/lex_llm/version.rb +0 -5
  162. data/lib/lex_llm.rb +0 -96
  163. data/lib/tasks/lex_llm.rake +0 -23
  164. /data/lib/{lex_llm → legion/extensions/llm}/aliases.json +0 -0
  165. /data/lib/{lex_llm → legion/extensions/llm}/models.json +0 -0
@@ -1,214 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LexLLM
4
- module Generators
5
- # Shared helpers for LexLLM generators
6
- module GeneratorHelpers
7
- def parse_model_mappings
8
- @model_names = {
9
- chat: 'Chat',
10
- message: 'Message',
11
- tool_call: 'ToolCall',
12
- model: 'Model'
13
- }
14
-
15
- model_mappings.each do |mapping|
16
- if mapping.include?(':')
17
- key, value = mapping.split(':', 2)
18
- @model_names[key.to_sym] = value.classify
19
- end
20
- end
21
-
22
- @model_names
23
- end
24
-
25
- %i[chat message tool_call model].each do |type|
26
- define_method("#{type}_model_name") do
27
- @model_names ||= parse_model_mappings
28
- @model_names[type]
29
- end
30
-
31
- define_method("#{type}_table_name") do
32
- table_name_for(send("#{type}_model_name"))
33
- end
34
-
35
- define_method("#{type}_variable_name") do
36
- variable_name_for(send("#{type}_model_name"))
37
- end
38
-
39
- define_method("#{type}_controller_class_name") do
40
- controller_class_name_for(send("#{type}_model_name"))
41
- end
42
-
43
- define_method("#{type}_job_class_name") do
44
- "#{variable_name_for(send("#{type}_model_name")).camelize}ResponseJob"
45
- end
46
-
47
- define_method("#{type}_partial") do
48
- partial_path_for(send("#{type}_model_name"))
49
- end
50
- end
51
-
52
- def acts_as_chat_declaration
53
- params = []
54
-
55
- add_association_params(params, :messages, message_table_name, message_model_name,
56
- owner_table: chat_table_name, owner_model_name: chat_model_name, plural: true)
57
- add_association_params(params, :model, model_table_name, model_model_name,
58
- owner_table: chat_table_name, owner_model_name: chat_model_name)
59
-
60
- "acts_as_chat#{" #{params.join(', ')}" if params.any?}"
61
- end
62
-
63
- def acts_as_message_declaration
64
- params = []
65
-
66
- add_association_params(params, :chat, chat_table_name, chat_model_name,
67
- owner_table: message_table_name, owner_model_name: message_model_name)
68
- add_association_params(params, :tool_calls, tool_call_table_name, tool_call_model_name,
69
- owner_table: message_table_name, owner_model_name: message_model_name, plural: true)
70
- add_association_params(params, :model, model_table_name, model_model_name,
71
- owner_table: message_table_name, owner_model_name: message_model_name)
72
-
73
- "acts_as_message#{" #{params.join(', ')}" if params.any?}"
74
- end
75
-
76
- def acts_as_model_declaration
77
- params = []
78
-
79
- add_association_params(params, :chats, chat_table_name, chat_model_name,
80
- owner_table: model_table_name, owner_model_name: model_model_name, plural: true)
81
-
82
- "acts_as_model#{" #{params.join(', ')}" if params.any?}"
83
- end
84
-
85
- def acts_as_tool_call_declaration
86
- params = []
87
-
88
- add_association_params(params, :message, message_table_name, message_model_name,
89
- owner_table: tool_call_table_name, owner_model_name: tool_call_model_name)
90
-
91
- "acts_as_tool_call#{" #{params.join(', ')}" if params.any?}"
92
- end
93
-
94
- def create_namespace_modules
95
- namespaces = []
96
-
97
- [chat_model_name, message_model_name, tool_call_model_name, model_model_name].each do |model_name|
98
- if model_name.include?('::')
99
- namespace = model_name.split('::').first
100
- namespaces << namespace unless namespaces.include?(namespace)
101
- end
102
- end
103
-
104
- namespaces.each do |namespace|
105
- module_path = "app/models/#{namespace.underscore}.rb"
106
- next if File.exist?(Rails.root.join(module_path))
107
-
108
- create_file module_path do
109
- <<~RUBY
110
- module #{namespace}
111
- def self.table_name_prefix
112
- "#{namespace.underscore}_"
113
- end
114
- end
115
- RUBY
116
- end
117
- end
118
- end
119
-
120
- def migration_version
121
- "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
122
- end
123
-
124
- def create_migration_class_name(table_name)
125
- "create_#{table_name}".camelize
126
- end
127
-
128
- def postgresql?
129
- ::ActiveRecord::Base.connection.adapter_name.downcase.include?('postgresql')
130
- rescue StandardError
131
- false
132
- end
133
-
134
- def mysql?
135
- ::ActiveRecord::Base.connection.adapter_name.downcase.include?('mysql')
136
- rescue StandardError
137
- false
138
- end
139
-
140
- def table_exists?(table_name)
141
- ::ActiveRecord::Base.connection.table_exists?(table_name)
142
- rescue StandardError
143
- false
144
- end
145
-
146
- private
147
-
148
- # rubocop:disable Metrics/ParameterLists
149
- def add_association_params(params, default_assoc, table_name, model_name,
150
- owner_table:, owner_model_name:, plural: false)
151
- assoc = plural ? table_name.to_sym : table_name.singularize.to_sym
152
- collection_association = collection_association?(default_assoc, plural)
153
- foreign_key = inferred_foreign_key(table_name, owner_table, collection_association)
154
- default_foreign_key = default_inferred_foreign_key(assoc, owner_model_name, collection_association)
155
-
156
- params << "#{default_assoc}: :#{assoc}" if assoc != default_assoc
157
- params << "#{default_assoc.to_s.singularize}_class: '#{model_name}'" if model_name != assoc.to_s.classify
158
- params << "#{default_assoc}_foreign_key: :#{foreign_key}" if foreign_key != default_foreign_key
159
- end
160
- # rubocop:enable Metrics/ParameterLists
161
-
162
- def collection_association?(default_assoc, plural)
163
- plural || default_assoc.to_s.pluralize == default_assoc.to_s
164
- end
165
-
166
- def inferred_foreign_key(table_name, owner_table, collection_association)
167
- return "#{table_name.singularize}_id" unless collection_association
168
-
169
- "#{owner_table.singularize}_id"
170
- end
171
-
172
- # Rails default inference:
173
- # belongs_to :assoc -> assoc_id
174
- # has_many/has_one -> owner demodulized model name + _id
175
- def default_inferred_foreign_key(association_name, owner_model_name, collection_association)
176
- return "#{association_name}_id" unless collection_association
177
-
178
- "#{owner_model_name.demodulize.underscore}_id"
179
- end
180
-
181
- # Convert namespaced model names to proper table names
182
- # e.g., "Assistant::Chat" -> "assistant_chats" (not "assistant/chats")
183
- def table_name_for(model_name)
184
- model_name.underscore.pluralize.tr('/', '_')
185
- end
186
-
187
- # Convert model name to instance variable name
188
- # e.g., "LLM::Chat" -> "llm_chat" (not "llm/chat")
189
- def variable_name_for(model_name)
190
- model_name.underscore.tr('/', '_')
191
- end
192
-
193
- # Convert model name to controller class name
194
- # For namespaced models, use Rails convention: "Llm::Chat" -> "Llm::ChatsController"
195
- # For regular models: "Chat" -> "ChatsController"
196
- def controller_class_name_for(model_name)
197
- if model_name.include?('::')
198
- parts = model_name.split('::')
199
- namespace = parts[0..-2].join('::')
200
- resource = parts.last.pluralize
201
- "#{namespace}::#{resource}Controller"
202
- else
203
- "#{model_name.pluralize}Controller"
204
- end
205
- end
206
-
207
- # Convert model name to partial path
208
- # e.g., "LLM::Message" -> "llm/message" (not "llm_message")
209
- def partial_path_for(model_name)
210
- "#{model_name.underscore.pluralize}/#{model_name.demodulize.underscore}"
211
- end
212
- end
213
- end
214
- end
@@ -1,109 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails/generators'
4
- require 'rails/generators/active_record'
5
- require_relative '../generator_helpers'
6
-
7
- module LexLLM
8
- module Generators
9
- # Generator for LexLLM Rails models and migrations
10
- class InstallGenerator < Rails::Generators::Base
11
- include Rails::Generators::Migration
12
- include LexLLM::Generators::GeneratorHelpers
13
-
14
- namespace 'lex_llm:install'
15
-
16
- source_root File.expand_path('templates', __dir__)
17
-
18
- argument :model_mappings, type: :array, default: [], banner: 'chat:ChatName message:MessageName ...'
19
-
20
- class_option :skip_active_storage, type: :boolean, default: false,
21
- desc: 'Skip ActiveStorage installation and attachment setup'
22
-
23
- desc 'Creates models and migrations for LexLLM Rails integration\n' \
24
- 'Usage: bin/rails g lex_llm:install [chat:ChatName] [message:MessageName] ...'
25
-
26
- def self.next_migration_number(dirname)
27
- ::ActiveRecord::Generators::Base.next_migration_number(dirname)
28
- end
29
-
30
- def create_migration_files
31
- migration_template 'create_chats_migration.rb.tt',
32
- "db/migrate/create_#{chat_table_name}.rb"
33
- migration_template 'create_messages_migration.rb.tt',
34
- "db/migrate/create_#{message_table_name}.rb"
35
- migration_template 'create_tool_calls_migration.rb.tt',
36
- "db/migrate/create_#{tool_call_table_name}.rb"
37
- migration_template 'create_models_migration.rb.tt',
38
- "db/migrate/create_#{model_table_name}.rb"
39
- migration_template 'add_references_to_chats_tool_calls_and_messages_migration.rb.tt',
40
- 'db/migrate/add_references_to_' \
41
- "#{chat_table_name}_#{tool_call_table_name}_and_#{message_table_name}.rb"
42
- end
43
-
44
- def create_model_files
45
- create_namespace_modules
46
-
47
- template 'chat_model.rb.tt', "app/models/#{chat_model_name.underscore}.rb"
48
- template 'message_model.rb.tt', "app/models/#{message_model_name.underscore}.rb"
49
- template 'tool_call_model.rb.tt', "app/models/#{tool_call_model_name.underscore}.rb"
50
-
51
- template 'model_model.rb.tt', "app/models/#{model_model_name.underscore}.rb"
52
- end
53
-
54
- def create_initializer
55
- template 'initializer.rb.tt', 'config/initializers/lex_llm.rb'
56
- end
57
-
58
- def create_convention_directories
59
- %w[agents tools schemas prompts].each do |name|
60
- empty_directory "app/#{name}"
61
- create_file "app/#{name}/.gitkeep" unless File.exist?(Rails.root.join("app/#{name}/.gitkeep"))
62
- end
63
- end
64
-
65
- def install_active_storage
66
- return if options[:skip_active_storage]
67
-
68
- say ' Installing ActiveStorage for file attachments...', :cyan
69
- rails_command 'active_storage:install'
70
- end
71
-
72
- def show_install_info
73
- say "\n ✅ LexLLM installed!", :green
74
-
75
- say ' ✅ ActiveStorage configured for file attachments support', :green unless options[:skip_active_storage]
76
-
77
- say "\n Next steps:", :yellow
78
- say ' 1. Run: bin/rails db:migrate'
79
- say ' 2. Run: bin/rails lex_llm:load_models'
80
- say ' 3. Install a lex-llm-* provider gem and configure its settings'
81
-
82
- say " 4. Start chatting: #{chat_model_name}.create!(model: 'your-provider-model').ask('Hello!')"
83
- say " 5. Optional UI: #{chat_ui_generator_command}"
84
-
85
- if options[:skip_active_storage]
86
- say "\n 📎 Note: ActiveStorage was skipped", :yellow
87
- say ' File attachments won\'t work without ActiveStorage.'
88
- say ' To enable later:'
89
- say ' 1. Run: bin/rails active_storage:install && bin/rails db:migrate'
90
- say " 2. Add to your #{message_model_name} model: has_many_attached :attachments"
91
- end
92
-
93
- say "\n 📚 Documentation: https://github.com/LegionIO/lex-llm", :cyan
94
-
95
- say "\n ❤️ Love LexLLM?", :magenta
96
- say ' • ⭐ Star on GitHub: https://github.com/LegionIO/lex-llm'
97
- say "\n"
98
- end
99
-
100
- private
101
-
102
- def chat_ui_generator_command
103
- mappings = model_mappings.join(' ')
104
- mappings = " #{mappings}" unless mappings.empty?
105
- "bin/rails generate lex_llm:chat_ui#{mappings}"
106
- end
107
- end
108
- end
109
- end
@@ -1,9 +0,0 @@
1
- class AddReferencesTo<%= "#{chat_model_name.gsub('::', '').pluralize}#{tool_call_model_name.gsub('::', '').pluralize}And#{message_model_name.gsub('::', '').pluralize}" %> < ActiveRecord::Migration<%= migration_version %>
2
- def change
3
- add_reference :<%= chat_table_name %>, :<%= model_table_name.singularize %>, foreign_key: true
4
- add_reference :<%= tool_call_table_name %>, :<%= message_table_name.singularize %>, null: false, foreign_key: true
5
- add_reference :<%= message_table_name %>, :<%= chat_table_name.singularize %>, null: false, foreign_key: true
6
- add_reference :<%= message_table_name %>, :<%= model_table_name.singularize %>, foreign_key: true
7
- add_reference :<%= message_table_name %>, :<%= tool_call_table_name.singularize %>, foreign_key: true
8
- end
9
- end
@@ -1,3 +0,0 @@
1
- class <%= chat_model_name %> < ApplicationRecord
2
- <%= acts_as_chat_declaration %>
3
- end
@@ -1,7 +0,0 @@
1
- class <%= create_migration_class_name(chat_table_name) %> < ActiveRecord::Migration<%= migration_version %>
2
- def change
3
- create_table :<%= chat_table_name %> do |t|
4
- t.timestamps
5
- end
6
- end
7
- end
@@ -1,19 +0,0 @@
1
- class <%= create_migration_class_name(message_table_name) %> < ActiveRecord::Migration<%= migration_version %>
2
- def change
3
- create_table :<%= message_table_name %> do |t|
4
- t.string :role, null: false
5
- t.text :content
6
- t.json :content_raw
7
- t.text :thinking_text
8
- t.text :thinking_signature
9
- t.integer :thinking_tokens
10
- t.integer :input_tokens
11
- t.integer :output_tokens
12
- t.integer :cached_tokens
13
- t.integer :cache_creation_tokens
14
- t.timestamps
15
- end
16
-
17
- add_index :<%= message_table_name %>, :role
18
- end
19
- end
@@ -1,39 +0,0 @@
1
- class <%= create_migration_class_name(model_table_name) %> < ActiveRecord::Migration<%= migration_version %>
2
- def change
3
- create_table :<%= model_table_name %> do |t|
4
- t.string :model_id, null: false
5
- t.string :name, null: false
6
- t.string :provider, null: false
7
- t.string :family
8
- t.datetime :model_created_at
9
- t.integer :context_window
10
- t.integer :max_output_tokens
11
- t.date :knowledge_cutoff
12
- <% if postgresql? %>
13
- t.jsonb :modalities, default: {}
14
- t.jsonb :capabilities, default: []
15
- t.jsonb :pricing, default: {}
16
- t.jsonb :metadata, default: {}
17
- <% elsif mysql? %>
18
- t.json :modalities
19
- t.json :capabilities
20
- t.json :pricing
21
- t.json :metadata
22
- <% else %>
23
- t.json :modalities, default: {}
24
- t.json :capabilities, default: []
25
- t.json :pricing, default: {}
26
- t.json :metadata, default: {}
27
- <% end %>
28
- t.timestamps
29
-
30
- t.index [ :provider, :model_id ], unique: true
31
- t.index :provider
32
- t.index :family
33
- <% if postgresql? -%>
34
- t.index :capabilities, using: :gin
35
- t.index :modalities, using: :gin
36
- <% end -%>
37
- end
38
- end
39
- end
@@ -1,21 +0,0 @@
1
- <%#- # Migration for creating tool_calls table with database-specific JSON handling -%>
2
- class <%= create_migration_class_name(tool_call_table_name) %> < ActiveRecord::Migration<%= migration_version %>
3
- def change
4
- create_table :<%= tool_call_table_name %> do |t|
5
- t.string :tool_call_id, null: false
6
- t.string :name, null: false
7
- t.text :thought_signature
8
- <% if postgresql? %>
9
- t.jsonb :arguments, default: {}
10
- <% elsif mysql? %>
11
- t.json :arguments
12
- <% else %>
13
- t.json :arguments, default: {}
14
- <% end %>
15
- t.timestamps
16
- end
17
-
18
- add_index :<%= tool_call_table_name %>, :tool_call_id, unique: true
19
- add_index :<%= tool_call_table_name %>, :name
20
- end
21
- end
@@ -1,20 +0,0 @@
1
- require "lex_llm"
2
- require "lex_llm/active_record/acts_as"
3
-
4
- LexLLM.configure do |config|
5
- # Provider gems register their own settings.
6
- # Example after installing a provider extension:
7
- # config.default_model = "your-provider-model"
8
-
9
- # Use the new association-based acts_as API (recommended)
10
- config.use_new_acts_as = true
11
- <% if model_model_name != 'Model' -%>
12
-
13
- # Custom model registry class name
14
- config.model_registry_class = "<%= model_model_name %>"
15
- <% end -%>
16
- end
17
-
18
- ActiveSupport.on_load :active_record do
19
- ::ActiveRecord::Base.include LexLLM::ActiveRecord::ActsAs
20
- end
@@ -1,4 +0,0 @@
1
- class <%= message_model_name %> < ApplicationRecord
2
- <%= acts_as_message_declaration %><% unless options[:skip_active_storage] %>
3
- has_many_attached :attachments<% end %>
4
- end
@@ -1,3 +0,0 @@
1
- class <%= model_model_name %> < ApplicationRecord
2
- <%= acts_as_model_declaration %>
3
- end
@@ -1,3 +0,0 @@
1
- class <%= tool_call_model_name %> < ApplicationRecord
2
- <%= acts_as_tool_call_declaration %>
3
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails/generators'
4
-
5
- module LexLLM
6
- module Generators
7
- # Generator for LexLLM schema classes.
8
- class SchemaGenerator < Rails::Generators::NamedBase
9
- source_root File.expand_path('templates', __dir__)
10
-
11
- namespace 'lex_llm:schema'
12
-
13
- desc 'Creates a LexLLM schema class'
14
-
15
- def create_schema_file
16
- template 'schema.rb.tt', File.join('app/schemas', class_path, "#{file_name}.rb")
17
- end
18
-
19
- private
20
-
21
- def schema_class_name
22
- class_name.end_with?('Schema') ? class_name : "#{class_name}Schema"
23
- end
24
- end
25
- end
26
- end
@@ -1,2 +0,0 @@
1
- class <%= schema_class_name %> < LexLLM::Schema
2
- end
@@ -1,9 +0,0 @@
1
- class <%= class_name %>Tool < LexLLM::Tool
2
- description "TODO: describe what this tool does"
3
-
4
- def execute
5
- # TODO: return something to the LLM.
6
- # Anything you return here gets converted to a string.
7
- "TODO: implement <%= class_name %>Tool"
8
- end
9
- end
@@ -1,13 +0,0 @@
1
- <%% tool_call_error = tool_call.tool_error_message %>
2
- <%% if tool_call_error.present? %>
3
- <%%= render "messages/error", message: tool_calls, title: "Tool Call Error", error_message: tool_call_error %>
4
- <%% else %>
5
- <div id="message_<%%= tool_calls.id %>" class="message"
6
- style="margin-bottom: 20px; padding: 10px; border-left: 3px solid #6b7280; background: #f9fafb;">
7
- <div style="font-weight: bold; margin-bottom: 5px;"><%= tool_display_name %> Call</div>
8
- <pre style="white-space: pre-wrap; margin: 0;"><%%= tool_call.name %>(<%%= tool_call.arguments.map { |k, v| "#{k}: #{v.inspect}" }.join(", ") %>)</pre>
9
- <div style="font-size: 0.85em; color: #666; margin-top: 5px;">
10
- <%%= tool_calls.created_at&.strftime("%I:%M %p") %>
11
- </div>
12
- </div>
13
- <%% end %>
@@ -1,13 +0,0 @@
1
- <%% error_message = tool.tool_error_message %>
2
- <%% if error_message.present? %>
3
- <%%= render "messages/error", message: tool, title: "Tool Result Error", error_message: error_message %>
4
- <%% else %>
5
- <div id="message_<%%= tool.id %>" class="message"
6
- style="margin-bottom: 20px; padding: 10px; border-left: 3px solid #6b7280; background: #f9fafb;">
7
- <div style="font-weight: bold; margin-bottom: 5px;"><%= tool_display_name %> Result</div>
8
- <pre style="white-space: pre-wrap; margin: 0;"><%%= tool.content.presence || "(no output)" %></pre>
9
- <div style="font-size: 0.85em; color: #666; margin-top: 5px;">
10
- <%%= tool.created_at&.strftime("%I:%M %p") %>
11
- </div>
12
- </div>
13
- <%% end %>
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails/generators'
4
-
5
- module LexLLM
6
- module Generators
7
- # Generator for LexLLM tool classes and related message partials.
8
- class ToolGenerator < Rails::Generators::NamedBase
9
- source_root File.expand_path('templates', __dir__)
10
-
11
- namespace 'lex_llm:tool'
12
-
13
- check_class_collision suffix: 'Tool'
14
-
15
- desc 'Creates a LexLLM tool class and matching tool call/result view partials'
16
-
17
- def create_tool_file
18
- template 'tool.rb.tt', File.join('app/tools', class_path, "#{file_name}_tool.rb")
19
- end
20
-
21
- def create_tool_view_partials
22
- empty_directory 'app/views/messages/tool_calls'
23
- empty_directory 'app/views/messages/tool_results'
24
-
25
- create_tool_call_partial
26
- create_tool_result_partial
27
- end
28
-
29
- private
30
-
31
- def create_tool_call_partial
32
- destination_path = File.join('app/views/messages/tool_calls', "_#{tool_partial_name}.html.erb")
33
- default_partial_path = File.join(destination_root, 'app/views/messages/tool_calls/_default.html.erb')
34
-
35
- if File.exist?(default_partial_path)
36
- default_markup = tool_named_call_markup(File.read(default_partial_path))
37
- indented_markup = indent_non_empty_lines(default_markup, 2)
38
- create_file destination_path, <<~ERB
39
- <% tool_call_error = tool_call.tool_error_message %>
40
- <% if tool_call_error.present? %>
41
- <%= render "messages/error", message: tool_calls, title: "Tool Call Error", error_message: tool_call_error %>
42
- <% else %>
43
- #{indented_markup}<% end %>
44
- ERB
45
- else
46
- template 'tool_call.html.erb.tt', destination_path
47
- end
48
-
49
- strip_trailing_whitespace(destination_path)
50
- end
51
-
52
- def create_tool_result_partial
53
- destination_path = File.join('app/views/messages/tool_results', "_#{tool_partial_name}.html.erb")
54
- default_partial_path = File.join(destination_root, 'app/views/messages/tool_results/_default.html.erb')
55
-
56
- if File.exist?(default_partial_path)
57
- create_file destination_path, tool_named_result_markup(File.read(default_partial_path))
58
- else
59
- template 'tool_result.html.erb.tt', destination_path
60
- end
61
-
62
- strip_trailing_whitespace(destination_path)
63
- end
64
-
65
- def tool_named_call_markup(markup)
66
- markup.sub('Tool Call', "#{tool_display_name} Call")
67
- end
68
-
69
- def tool_named_result_markup(markup)
70
- markup.sub(/\bTool\b(?!\s*Result)/, "#{tool_display_name} Result")
71
- end
72
-
73
- def tool_display_name
74
- class_name.demodulize
75
- end
76
-
77
- def tool_partial_name
78
- file_name.delete_suffix('_tool')
79
- end
80
-
81
- def indent_non_empty_lines(markup, spaces)
82
- indentation = ' ' * spaces
83
- markup.lines.map { |line| line.strip.empty? ? line : "#{indentation}#{line}" }.join
84
- end
85
-
86
- def strip_trailing_whitespace(path)
87
- content = File.read(path)
88
- stripped_content = content.lines.map(&:rstrip).join("\n")
89
- stripped_content = "#{stripped_content}\n" unless stripped_content.end_with?("\n")
90
- return if content == stripped_content
91
-
92
- File.write(path, stripped_content)
93
- end
94
- end
95
- end
96
- end
@@ -1,19 +0,0 @@
1
- class AddLexLlmV110Columns < ActiveRecord::Migration<%= migration_version %>
2
- def change
3
- unless column_exists?(:<%= message_table_name %>, :thinking_text)
4
- add_column :<%= message_table_name %>, :thinking_text, :text
5
- end
6
-
7
- unless column_exists?(:<%= message_table_name %>, :thinking_signature)
8
- add_column :<%= message_table_name %>, :thinking_signature, :text
9
- end
10
-
11
- unless column_exists?(:<%= message_table_name %>, :thinking_tokens)
12
- add_column :<%= message_table_name %>, :thinking_tokens, :integer
13
- end
14
-
15
- unless column_exists?(:<%= tool_call_table_name %>, :thought_signature)
16
- add_column :<%= tool_call_table_name %>, :thought_signature, :string
17
- end
18
- end
19
- end